From 19be985731fe8a41fbe100fb1edf7f1fa1c7560e Mon Sep 17 00:00:00 2001 From: Andy Howard Date: Fri, 14 May 2021 13:17:39 +0100 Subject: [PATCH] Data project added (previously Office) --- SaCommonVS.sln | 8 +- SacsStandardBase/Base/Bus/SysId.cs | 20 +- SacsStandardBase/Base/Dbas/DbDfnColumn.cs | 55 +- SacsStandardBase/Base/Dbas/DbDfnIndex.cs | 24 +- SacsStandardBase/Base/Dbas/DbDfnTable.cs | 89 +- SacsStandardBase/Base/Dbas/OdbcUtil.cs | 9 +- SacsStandardBase/Base/Utils/StringUtil.cs | 12 + SacsStandardData/Data/Excel/MsExcel.cs | 1143 +++++++++++++++++ .../Data/Excel/SaMsSpreadsheet-Dfn.cs | 206 +++ .../Data/Excel/SaMsSpreadsheet.cs | 569 ++++++++ .../Data/Excel/SaMsSpreadsheet_Direct.cs | 909 +++++++++++++ .../Data/Excel/SaMsSpreadsheet_OpenXml.cs | 656 ++++++++++ SacsStandardData/Data/Xml/SaMsXmlDocument.cs | 121 ++ SacsStandardData/Data/Xml/SaMsXmlElement.cs | 178 +++ SacsStandardData/Data/Xml/SaMsXmlNode.cs | 122 ++ SacsStandardData/Data/Xml/SaMsXmlUtil.cs | 125 ++ SacsStandardData/Data/Zip/SaMsZipArchive.cs | 123 ++ SacsStandardData/SacsStandardData.csproj | 21 + .../Dbas/Base/DatabaseDefinitionGenerator.cs | 6 +- .../Dbas/Data/SacsDatabaseOdbc.cs | 4 +- 20 files changed, 4330 insertions(+), 70 deletions(-) create mode 100644 SacsStandardData/Data/Excel/MsExcel.cs create mode 100644 SacsStandardData/Data/Excel/SaMsSpreadsheet-Dfn.cs create mode 100644 SacsStandardData/Data/Excel/SaMsSpreadsheet.cs create mode 100644 SacsStandardData/Data/Excel/SaMsSpreadsheet_Direct.cs create mode 100644 SacsStandardData/Data/Excel/SaMsSpreadsheet_OpenXml.cs create mode 100644 SacsStandardData/Data/Xml/SaMsXmlDocument.cs create mode 100644 SacsStandardData/Data/Xml/SaMsXmlElement.cs create mode 100644 SacsStandardData/Data/Xml/SaMsXmlNode.cs create mode 100644 SacsStandardData/Data/Xml/SaMsXmlUtil.cs create mode 100644 SacsStandardData/Data/Zip/SaMsZipArchive.cs create mode 100644 SacsStandardData/SacsStandardData.csproj diff --git a/SaCommonVS.sln b/SaCommonVS.sln index a372705..dbb9e39 100644 --- a/SaCommonVS.sln +++ b/SaCommonVS.sln @@ -18,7 +18,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution files", "Solution ReadMe.md = ReadMe.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SacsStandardAccounts", "SacsStandardAccounts\SacsStandardAccounts.csproj", "{C62999E2-1947-4EB7-82D2-A0EDB67D2F10}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardAccounts", "SacsStandardAccounts\SacsStandardAccounts.csproj", "{C62999E2-1947-4EB7-82D2-A0EDB67D2F10}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SacsStandardData", "SacsStandardData\SacsStandardData.csproj", "{1EF60484-61DB-4BDC-8BF2-394C663B6031}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -50,6 +52,10 @@ Global {C62999E2-1947-4EB7-82D2-A0EDB67D2F10}.Debug|Any CPU.Build.0 = Debug|Any CPU {C62999E2-1947-4EB7-82D2-A0EDB67D2F10}.Release|Any CPU.ActiveCfg = Release|Any CPU {C62999E2-1947-4EB7-82D2-A0EDB67D2F10}.Release|Any CPU.Build.0 = Release|Any CPU + {1EF60484-61DB-4BDC-8BF2-394C663B6031}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1EF60484-61DB-4BDC-8BF2-394C663B6031}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1EF60484-61DB-4BDC-8BF2-394C663B6031}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1EF60484-61DB-4BDC-8BF2-394C663B6031}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SacsStandardBase/Base/Bus/SysId.cs b/SacsStandardBase/Base/Bus/SysId.cs index 004b2fa..34afe4d 100644 --- a/SacsStandardBase/Base/Bus/SysId.cs +++ b/SacsStandardBase/Base/Bus/SysId.cs @@ -12,12 +12,12 @@ namespace Sarand.Net.Standard.Base.Bus { //------------------------------------------------------------------- // Data members. - private int id = 0; + private Int64 id = 0; //------------------------------------------------------------------- // Construction. public SysId () { } - public SysId (int id) + public SysId (Int64 id) { this.id = id; } @@ -25,7 +25,7 @@ namespace Sarand.Net.Standard.Base.Bus //------------------------------------------------------------------- // Properties - for serialisation. //[XmlAttribute] - public int Id + public Int64 Id { get { return id; } set @@ -62,12 +62,16 @@ namespace Sarand.Net.Standard.Base.Bus } public override int GetHashCode () { - return id; + return id.GetHashCode(); } //------------------------------------------------------------------- // Conversion. - public int ToInt () + public Int64 ToLong() + { + return ToInt(this); + } + public Int32 ToInt() { return ToInt(this); } @@ -80,7 +84,11 @@ namespace Sarand.Net.Standard.Base.Bus return ToString(this, invalidValue); } // Null-safe static versions. - public static int ToInt (SysId sysId) + public static Int32 ToInt(SysId sysId) + { + return (IsValid(sysId) ? (Int32)sysId.id : 0); + } + public static Int64 ToLong(SysId sysId) { return (IsValid(sysId) ? sysId.id : 0); } diff --git a/SacsStandardBase/Base/Dbas/DbDfnColumn.cs b/SacsStandardBase/Base/Dbas/DbDfnColumn.cs index 8a69a11..7f2b51e 100644 --- a/SacsStandardBase/Base/Dbas/DbDfnColumn.cs +++ b/SacsStandardBase/Base/Dbas/DbDfnColumn.cs @@ -11,24 +11,24 @@ namespace Sarand.Net.Standard.Base.Dbas { // Ref. https://msdn.microsoft.com/en-us/library/yy6y35y8%28v=vs.110%29.aspx Unknown = -1, - VarChar, //SQL_C_CHAR, - Bit, // SQL_C_BIT, - TinyInt, // SQL_C_TINYINT, - SmallInt, // SQL_C_SHORT, - Int, //SQL_C_SLONG, - BigInt, // SQL_C_SBIGINT, - Single, // SQL_C_REAL, - Double, // SQL_C_DOUBLE, + VarChar, // SQL_C_CHAR, + Bit, // SQL_C_BIT, + TinyInt, // SQL_C_TINYINT, + SmallInt, // SQL_C_SHORT, + Int, // SQL_C_SLONG, + BigInt, // SQL_C_SBIGINT, + Single, // SQL_C_REAL, + Double, // SQL_C_DOUBLE, Decimal, // SQL_DECIMAL?, - DateTime, // SQL_C_TYPE_TIMESTAMP + DateTime, // SQL_C_TYPE_TIMESTAMP Binary, }; //[Serializable()] public enum DbColumnNullable { - NoNulls = 0, // SQL_NO_NULLS, - Nullable = 1, // SQL_NULLABLE, - Unknown = 2, // SQL_NULLABLE_UNKNOWN, // Not known whether or not a data type supports null values. + NoNulls = 0, // SQL_NO_NULLS, + Nullable = 1, // SQL_NULLABLE, + Unknown = 2, // SQL_NULLABLE_UNKNOWN, // Not known whether or not a data type supports null values. }; //========================================================================== //[Serializable()] @@ -38,8 +38,8 @@ namespace Sarand.Net.Standard.Base.Dbas // Data members. //------------------------------------------------------------------- // Construction. - public DbDfnColumn () { } - public DbDfnColumn (String schema, String table, short pos, String name) + public DbDfnColumn() { } + public DbDfnColumn(String schema, String table, short pos, String name) { Schema = schema; Table = table; @@ -65,7 +65,7 @@ namespace Sarand.Net.Standard.Base.Dbas public String Remarks { get; set; } = String.Empty; //------------------------------------------------------------------- // Variable type and default - used in variable declaration. - public String GetVariableTypeName () + public String GetVariableTypeName() { switch (DataType) { @@ -74,7 +74,7 @@ namespace Sarand.Net.Standard.Base.Dbas } return GetVariableType(); } - public String GetVariableType () + public String GetVariableType() { switch (DataType) { @@ -103,7 +103,7 @@ namespace Sarand.Net.Standard.Base.Dbas } return String.Empty; } - public String GetVariableDefault () + public String GetVariableDefault() { switch (DataType) { @@ -132,7 +132,7 @@ namespace Sarand.Net.Standard.Base.Dbas } return String.Empty; } - public String GetGetFieldSuffix () + public String GetGetFieldSuffix() { switch (DataType) { @@ -159,7 +159,7 @@ namespace Sarand.Net.Standard.Base.Dbas public static class DbDfnColumnList { // List of column names. - public static List GetNames (this List columns) + public static List GetNames(this List columns) { List names = new List(); foreach (var column in columns) @@ -169,7 +169,7 @@ namespace Sarand.Net.Standard.Base.Dbas return names; } // Identity column. - public static String GetIdentityColumnName (this List columns) + public static String GetIdentityColumnName(this List columns) { List names = new List(); foreach (var column in columns) @@ -179,8 +179,19 @@ namespace Sarand.Net.Standard.Base.Dbas } return String.Empty; } + public static String GetIdentityColumnVariableTypeName(this List columns) + { + List names = new List(); + foreach (var column in columns) + { + if (column.IsIdentity) + return column.GetVariableTypeName(); + } + return String.Empty; + } + // Locate the column in the list: - public static DbDfnColumn GetColumnByPos (this List columns, short pos) + public static DbDfnColumn GetColumnByPos(this List columns, short pos) { foreach (var column in columns) { @@ -189,7 +200,7 @@ namespace Sarand.Net.Standard.Base.Dbas } return null; } - public static DbDfnColumn GetColumnByName (this List columns, String name) + public static DbDfnColumn GetColumnByName(this List columns, String name) { foreach (var column in columns) { diff --git a/SacsStandardBase/Base/Dbas/DbDfnIndex.cs b/SacsStandardBase/Base/Dbas/DbDfnIndex.cs index 40cd1d7..cef6076 100644 --- a/SacsStandardBase/Base/Dbas/DbDfnIndex.cs +++ b/SacsStandardBase/Base/Dbas/DbDfnIndex.cs @@ -21,6 +21,7 @@ namespace Sarand.Net.Standard.Base.Dbas //------------------------------------------------------------------- // Data members. private readonly List columns = new List(); + //------------------------------------------------------------------- // Construction. public DbDfnIndex () { } @@ -31,6 +32,7 @@ namespace Sarand.Net.Standard.Base.Dbas Name = name; Unique = unique; } + //------------------------------------------------------------------- // Attributes. public String Schema { get; set; } = String.Empty; @@ -44,23 +46,36 @@ namespace Sarand.Net.Standard.Base.Dbas public int Pages { get; set; } = 0; public int UniqueValues { get; set; } = 0; public bool HasColumns { get; set; } = false; + //------------------------------------------------------------------- // Columns. public List Columns { - get { return columns; } - set { columns.Clear(); columns.AddRange(value); } + get + { + lock (columns) + return new List(columns); + } + set + { + lock (columns) + columns.Clear(); columns.AddRange(value); + } } public void CearColumns () { - columns.Clear(); + lock (columns) + columns.Clear(); } public void AddColumn (DbDfnIndexColumn column) { - columns.Add(column); + lock (columns) + columns.Add(column); } + //------------------------------------------------------------------- } + //======================================================================= // Index list extensions. public static class DbDfnIndexList @@ -92,5 +107,6 @@ namespace Sarand.Net.Standard.Base.Dbas return index; } } + //======================================================================= } diff --git a/SacsStandardBase/Base/Dbas/DbDfnTable.cs b/SacsStandardBase/Base/Dbas/DbDfnTable.cs index ade6286..4f530fb 100644 --- a/SacsStandardBase/Base/Dbas/DbDfnTable.cs +++ b/SacsStandardBase/Base/Dbas/DbDfnTable.cs @@ -16,8 +16,8 @@ namespace Sarand.Net.Standard.Base.Dbas //------------------------------------------------------------------- // Construction. - public DbDfnTable () { } - public DbDfnTable (String schema, String name, String remarks) + public DbDfnTable() { } + public DbDfnTable(String schema, String name, String remarks) { this.Schema = schema; this.Name = name; @@ -33,41 +33,53 @@ namespace Sarand.Net.Standard.Base.Dbas //------------------------------------------------------------------- // Comparison. - public bool MatchesSchemaName (String schema, String name) + public bool MatchesSchemaName(String schema, String name) { return (this.Schema.EqualsCI(schema) && this.Name.EqualsCI(name)); } - public bool MatchesName (String name) + public bool MatchesName(String name) { return (this.Name.EqualsCI(name)); } //------------------------------------------------------------------- // Columns. - public bool HasColumnByName (String columnName) + public bool HasColumnByName(String columnName) { - return (columns != null && columns.Exists(col => col.Name.EqualsCI(columnName))); + lock (columns) + return (columns != null && columns.Exists(col => col.Name.EqualsCI(columnName))); } - public bool HasColumns () + public bool HasColumns() { - return (columns != null && columns.Count > 0); + lock (columns) + return (columns != null && columns.Count > 0); } public List Columns { - get { return new List(columns); } - set { columns.Clear(); columns.AddRange(value); } + get + { + lock (columns) + return new List(columns); + } + set + { + lock (columns) + columns.Clear(); columns.AddRange(value); + } } - public void CearColumns () + public void CearColumns() { - columns.Clear(); + lock (columns) + columns.Clear(); } - public void AddColumn (DbDfnColumn column) + public void AddColumn(DbDfnColumn column) { - columns.Add(column); + lock (columns) + columns.Add(column); } - public List GetPrimaryColumnNames () + public List GetPrimaryColumnNames() { - ListprimaryColumnNames = new List(); + List primaryColumnNames = new List(); // Identify primary index. var index = Indices.GetPrimaryIndex(); if (index == null) index = indices.GetClusteredIndex(); @@ -82,26 +94,43 @@ namespace Sarand.Net.Standard.Base.Dbas //------------------------------------------------------------------- // Indices. - public bool HasIndexByName (String indexName) + public bool HasIndexByName(String indexName) { - return (indices != null && indices.Exists(idx => idx.Name.EqualsCI(indexName))); + lock (indices) + return (indices != null && indices.Exists(idx => idx.Name.EqualsCI(indexName))); + } + public bool HasIndices() + { + lock (indices) + return (indices != null && indices.Count > 0); } public List Indices { - get { return new List(indices); } - set { indices.Clear(); indices.AddRange(value); } + get + { + lock (indices) + return new List(indices); + } + set + { + lock (indices) + indices.Clear(); indices.AddRange(value); + } } - public DbDfnIndex GetIndexByName (String name) + public DbDfnIndex GetIndexByName(String name) { - return indices.GetIndexByName(name); + lock (indices) + return indices.GetIndexByName(name); } - public void CearIndices () + public void CearIndices() { - indices.Clear(); + lock (indices) + indices.Clear(); } - public void AddIndex (DbDfnIndex Index) + public void AddIndex(DbDfnIndex Index) { - indices.Add(Index); + lock (indices) + indices.Add(Index); } //------------------------------------------------------------------- @@ -112,7 +141,7 @@ namespace Sarand.Net.Standard.Base.Dbas { //------------------------------------------------------------------- /// List of table names. - public static List GetNames (this List tables) + public static List GetNames(this List tables) { List names = new List(); foreach (DbDfnTable table in tables) @@ -124,7 +153,7 @@ namespace Sarand.Net.Standard.Base.Dbas //------------------------------------------------------------------- /// Extract the table definition by schema and table name. - public static DbDfnTable GetTableBySchemaName (this List tables, String schema, String name) + public static DbDfnTable GetTableBySchemaName(this List tables, String schema, String name) { foreach (DbDfnTable table in tables) { @@ -134,7 +163,7 @@ namespace Sarand.Net.Standard.Base.Dbas return null; } /// Extract the table definition by table name. - public static DbDfnTable GetTableByName (this List tables, String name) + public static DbDfnTable GetTableByName(this List tables, String name) { foreach (DbDfnTable table in tables) { @@ -146,7 +175,7 @@ namespace Sarand.Net.Standard.Base.Dbas //------------------------------------------------------------------- /// Get total number of columns for all tables. - public static int GetColumnCount (this List tables) + public static int GetColumnCount(this List tables) { int columnCount = 0; foreach (DbDfnTable table in tables) diff --git a/SacsStandardBase/Base/Dbas/OdbcUtil.cs b/SacsStandardBase/Base/Dbas/OdbcUtil.cs index b8242ad..ebcdb10 100644 --- a/SacsStandardBase/Base/Dbas/OdbcUtil.cs +++ b/SacsStandardBase/Base/Dbas/OdbcUtil.cs @@ -144,10 +144,14 @@ namespace Sarand.Net.Standard.Base.Dbas type = DbColumnDataType.SmallInt; break; //--------------------------------------------------------------- - case 4: // SQL_INTEGER: // 4 INTEGER Exact numeric value with precision 10 and scale 0 (signed: –2[31] <= n <= 2[31] – 1, unsigned:0 <= n <= 2[32] – 1)[3]. + case 4: // SQL_INTEGER: // 4 INTEGER Exact numeric value with precision 10 and scale 0 (signed: –2[31] <= n <= 2[31] – 1, unsigned:0 <= n <= 2[32] – 1)[3]. type = DbColumnDataType.Int; break; //--------------------------------------------------------------- + case -5: // SQL_BIGINT: // -5 BIGINT Exact numeric value with precision 19 (if signed) or 20 (if unsigned) and scale 0 (signed: –2[63] <= n <= 2[63] – 1, unsigned:0 <= n <= 2[64] – 1)[3],[9]. + type = DbColumnDataType.BigInt; + break; + //--------------------------------------------------------------- case 7: // SQL_REAL: // 7 REAL Signed, approximate, numeric value with a binary precision 24 (zero or absolute value 10[–38] to 10[38]). type = DbColumnDataType.Single; break; @@ -175,7 +179,6 @@ namespace Sarand.Net.Standard.Base.Dbas type = DbColumnDataType.Binary; break; //--------------------------------------------------------------- - case -5: // SQL_BIGINT: // -5 BIGINT Exact numeric value with precision 19 (if signed) or 20 (if unsigned) and scale 0 (signed: –2[63] <= n <= 2[63] – 1, unsigned:0 <= n <= 2[64] – 1)[3],[9]. case 102: // SQL_INTERVAL_MONTH: // 102 INTERVAL MONTH(p) Number of months between two dates; p is the interval leading precision. case 101: // SQL_INTERVAL_YEAR: // 101 INTERVAL YEAR(p) Number of years between two dates; p is the interval leading precision. case 107: // SQL_INTERVAL_YEAR_TO_MONTH: // 107 INTERVAL YEAR(p) TO MONTH Number of years and months between two dates; p is the interval leading precision. @@ -190,7 +193,7 @@ namespace Sarand.Net.Standard.Base.Dbas case 112: // SQL_INTERVAL_HOUR_TO_SECOND: // 112 INTERVAL HOUR(p) TO SECOND(q) Number of hours/minutes/seconds between two date/times; p is the interval leading precision and q is the interval seconds precision. case 113: // SQL_INTERVAL_MINUTE_TO_SECOND: // 113 INTERVAL MINUTE(p) TO SECOND(q) Number of minutes/seconds between two date/times; p is the interval leading precision and q is the interval seconds precision. case -11: // SQL_GUID: // -11 GUID Fixed length Globally Unique Identifier. - break; + // break; //--------------------------------------------------------------- default: SaLogger.Debug("OdbcUtil.OdbcToDataType Unrecognised native data type: " + dataType); diff --git a/SacsStandardBase/Base/Utils/StringUtil.cs b/SacsStandardBase/Base/Utils/StringUtil.cs index ebc26d9..616ccfc 100644 --- a/SacsStandardBase/Base/Utils/StringUtil.cs +++ b/SacsStandardBase/Base/Utils/StringUtil.cs @@ -1,4 +1,5 @@ using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Bus; using Sarand.Net.Standard.Base.Core; using System; using System.Globalization; @@ -282,6 +283,14 @@ namespace Sarand.Net.Standard.Base.Utils catch (Exception) { } return defaultValue; } + + //--------------------------------------------------------------------------- + // SysId. + public static SysId ToSysId(this String value) + { + return new SysId(StringUtil.ToLong(value)); + } + //--------------------------------------------------------------------------- // Hex values to integer. /// Convert hex character to integer value. @@ -312,6 +321,7 @@ namespace Sarand.Net.Standard.Base.Utils } return intValue; } + //------------------------------------------------------------------- // Floating point values. public static float ToSingle (this string value, float defaultValue = 0) @@ -344,6 +354,7 @@ namespace Sarand.Net.Standard.Base.Utils catch (Exception) { } return defaultValue; } + //------------------------------------------------------------------- // Decimal values. public static decimal ToDecimal (this string value, decimal defaultValue = 0) @@ -368,6 +379,7 @@ namespace Sarand.Net.Standard.Base.Utils catch (Exception) { } return defaultValue; } + //------------------------------------------------------------------- // Boolean values. public static bool ToBool (this string value) diff --git a/SacsStandardData/Data/Excel/MsExcel.cs b/SacsStandardData/Data/Excel/MsExcel.cs new file mode 100644 index 0000000..7e9eb1f --- /dev/null +++ b/SacsStandardData/Data/Excel/MsExcel.cs @@ -0,0 +1,1143 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Sarand.Net.Standard.Data.Excel +{ + //======================================================================= + // MS Excel constant definitions. + // Ref. namespace Microsoft.Office.Interop.Excel + //======================================================================= + // + // Summary: + // Specifies the file format when saving the spreadsheet. + public enum XlFileFormat + { + // + // Summary: + // Specifies a type of text format + xlCurrentPlatformText = -4158, + // + // Summary: + // Excel workbook format. + xlWorkbookNormal = -4143, + // + // Summary: + // Symbolic link format. + xlSYLK = 2, + // + // Summary: + // Lotus 1-2-3 format. + xlWKS = 4, + // + // Summary: + // Lotus 1-2-3 format. + xlWK1 = 5, + // + // Summary: + // Comma separated value. + xlCSV = 6, + // + // Summary: + // Dbase 2 format. + xlDBF2 = 7, + // + // Summary: + // Dbase 3 format. + xlDBF3 = 8, + // + // Summary: + // Data Interchange format. + xlDIF = 9, + // + // Summary: + // Dbase 4 format. + xlDBF4 = 11, + // + // Summary: + // Deprecated format. + xlWJ2WD1 = 14, + // + // Summary: + // Lotus 1-2-3 format. + xlWK3 = 15, + // + // Summary: + // Excel version 2.0. + xlExcel2 = 16, + // + // Summary: + // Excel template format. + xlTemplate = 17, + // + // Summary: + // Template 8 + xlTemplate8 = 17, + // + // Summary: + // Microsoft Office Excel Add-In. + xlAddIn = 18, + // + // Summary: + // Microsoft Excel 97-2003 Add-In + xlAddIn8 = 18, + // + // Summary: + // Specifies a type of text format. + xlTextMac = 19, + // + // Summary: + // Specifies a type of text format. + xlTextWindows = 20, + // + // Summary: + // Specifies a type of text format. + xlTextMSDOS = 21, + // + // Summary: + // Comma separated value. + xlCSVMac = 22, + // + // Summary: + // Comma separated value. + xlCSVWindows = 23, + // + // Summary: + // Comma separated value. + xlCSVMSDOS = 24, + // + // Summary: + // Deprecated format. + xlIntlMacro = 25, + // + // Summary: + // Microsoft Office Excel Add-In international format. + xlIntlAddIn = 26, + // + // Summary: + // Excel version 2.0 far east. + xlExcel2FarEast = 27, + // + // Summary: + // Microsoft Works 2.0 format + xlWorks2FarEast = 28, + // + // Summary: + // Excel version 3.0. + xlExcel3 = 29, + // + // Summary: + // Lotus 1-2-3 format. + xlWK1FMT = 30, + // + // Summary: + // Lotus 1-2-3 format. + xlWK1ALL = 31, + // + // Summary: + // Lotus 1-2-3 format. + xlWK3FM3 = 32, + // + // Summary: + // Excel version 4.0. + xlExcel4 = 33, + // + // Summary: + // Quattro Pro format. + xlWQ1 = 34, + // + // Summary: + // Excel version 4.0. Workbook format. + xlExcel4Workbook = 35, + // + // Summary: + // Specifies a type of text format. + xlTextPrinter = 36, + // + // Summary: + // Lotus 1-2-3 format. + xlWK4 = 38, + // + // Summary: + // Excel version 5.0. + xlExcel5 = 39, + // + // Summary: + // Excel 95. + xlExcel7 = 39, + // + // Summary: + // Deprecated format. + xlWJ3 = 40, + // + // Summary: + // Deprecated format. + xlWJ3FJ3 = 41, + // + // Summary: + // Specifies a type of text format. + xlUnicodeText = 42, + // + // Summary: + // Excel version 95 and 97. + xlExcel9795 = 43, + // + // Summary: + // Web page format. + xlHtml = 44, + // + // Summary: + // MHT format. + xlWebArchive = 45, + // + // Summary: + // Excel Spreadsheet format. + xlXMLSpreadsheet = 46, + // + // Summary: + // Excel12 + xlExcel12 = 50, + // + // Summary: + // Open XML Workbook + xlOpenXMLWorkbook = 51, + // + // Summary: + // Workbook default + xlWorkbookDefault = 51, + // + // Summary: + // Open XML Workbook Macro Enabled + xlOpenXMLWorkbookMacroEnabled = 52, + // + // Summary: + // Open XML Template Macro Enabled + xlOpenXMLTemplateMacroEnabled = 53, + // + // Summary: + // Open XML Template + xlOpenXMLTemplate = 54, + // + // Summary: + // Open XML Add-In + xlOpenXMLAddIn = 55, + // + // Summary: + // Excel8 + xlExcel8 = 56, + // + // Summary: + // OpenDocument Spreadsheet + xlOpenDocumentSpreadsheet = 60 + } + + //======================================================================= + // + // Summary: + // Specifies the page orientation when the worksheet is printed. + public enum XlPageOrientation + { + // + // Summary: + // Portrait mode. + xlPortrait = 1, + // + // Summary: + // Landscape mode. + xlLandscape = 2 + } + + //======================================================================= + // + // Summary: + // Specifies the weight of the border around a range. + public enum XlBorderWeight + { + // + // Summary: + // Medium. + xlMedium = -4138, + // + // Summary: + // Hairline (thinnest border). + xlHairline = 1, + // + // Summary: + // Thin. + xlThin = 2, + // + // Summary: + // Thick (widest border). + xlThick = 4 + } + + //======================================================================= + // + // Summary: + // Specifies the line style for the border. + public enum XlLineStyle + { + // + // Summary: + // No line. + xlLineStyleNone = -4142, + // + // Summary: + // Double line. + xlDouble = -4119, + // + // Summary: + // Dotted line. + xlDot = -4118, + // + // Summary: + // Dashed line. + xlDash = -4115, + // + // Summary: + // Continuous line. + xlContinuous = 1, + // + // Summary: + // Alternating dashes and dots. + xlDashDot = 4, + // + // Summary: + // Dash followed by two dots. + xlDashDotDot = 5, + // + // Summary: + // Slanted dashes. + xlSlantDashDot = 13 + } + + //======================================================================= + // + // Summary: + // Specifies the type of underline applied to a font. + public enum XlUnderlineStyle + { + // + // Summary: + // No underlining. + xlUnderlineStyleNone = -4142, + // + // Summary: + // Double thick underline. + xlUnderlineStyleDouble = -4119, + // + // Summary: + // Single underlining. + xlUnderlineStyleSingle = 2, + // + // Summary: + // Not supported. + xlUnderlineStyleSingleAccounting = 4, + // + // Summary: + // Two thin underlines placed close together. + xlUnderlineStyleDoubleAccounting = 5 + } + + //======================================================================= + // + // Summary: + // Specifies the horizontal alignment for the object. + public enum XlHAlign + { + // + // Summary: + // Right. + xlHAlignRight = -4152, + // + // Summary: + // Left. + xlHAlignLeft = -4131, + // + // Summary: + // Justify. + xlHAlignJustify = -4130, + // + // Summary: + // Distribute. + xlHAlignDistributed = -4117, + // + // Summary: + // Center. + xlHAlignCenter = -4108, + // + // Summary: + // Align according to data type. + xlHAlignGeneral = 1, + // + // Summary: + // Fill. + xlHAlignFill = 5, + // + // Summary: + // Center across selection. + xlHAlignCenterAcrossSelection = 7 + } + + //======================================================================= + // + // Summary: + // Specifies the vertical alignment for the object. + public enum XlVAlign + { + // + // Summary: + // Top. + xlVAlignTop = -4160, + // + // Summary: + // Justify. + xlVAlignJustify = -4130, + // + // Summary: + // Distributed. + xlVAlignDistributed = -4117, + // + // Summary: + // Center. + xlVAlignCenter = -4108, + // + // Summary: + // Bottom. + xlVAlignBottom = -4107 + } + + //======================================================================= + // + // Summary: + // Specifies the border to be retrieved. + public enum XlBordersIndex + { + // + // Summary: + // Border running from the upper left-hand corner to the lower right of each cell + // in the range. + xlDiagonalDown = 5, + // + // Summary: + // Border running from the lower left-hand corner to the upper right of each cell + // in the range. + xlDiagonalUp = 6, + // + // Summary: + // Border at the left-hand edge of the range. + xlEdgeLeft = 7, + // + // Summary: + // Border at the top of the range. + xlEdgeTop = 8, + // + // Summary: + // Border at the bottom of the range. + xlEdgeBottom = 9, + // + // Summary: + // Border at the right-hand edge of the range. + xlEdgeRight = 10, + // + // Summary: + // Vertical borders for all the cells in the range except borders on the outside + // of the range. + xlInsideVertical = 11, + // + // Summary: + // Horizontal borders for all cells in the range except borders on the outside of + // the range. + xlInsideHorizontal = 12 + } + + //======================================================================= + // + // Summary: + // Specifies the interior pattern of a chart or interior object. + public enum XlPattern + { + // + // Summary: + // Dark vertical bars. + xlPatternVertical = -4166, + // + // Summary: + // Dark diagonal lines running from the lower left to the upper right. + xlPatternUp = -4162, + // + // Summary: + // No pattern. + xlPatternNone = -4142, + // + // Summary: + // Dark horizontal lines. + xlPatternHorizontal = -4128, + // + // Summary: + // 75% gray. + xlPatternGray75 = -4126, + // + // Summary: + // 50% gray. + xlPatternGray50 = -4125, + // + // Summary: + // 25% gray. + xlPatternGray25 = -4124, + // + // Summary: + // Dark diagonal lines running from the upper left to the lower right. + xlPatternDown = -4121, + // + // Summary: + // Excel controls the pattern. + xlPatternAutomatic = -4105, + // + // Summary: + // Solid color. + xlPatternSolid = 1, + // + // Summary: + // Checkerboard. + xlPatternChecker = 9, + // + // Summary: + // 75% dark moiré. + xlPatternSemiGray75 = 10, + // + // Summary: + // Light horizontal lines. + xlPatternLightHorizontal = 11, + // + // Summary: + // Light vertical bars. + xlPatternLightVertical = 12, + // + // Summary: + // Light diagonal lines running from the upper left to the lower right. + xlPatternLightDown = 13, + // + // Summary: + // Light diagonal lines running from the lower left to the upper right. + xlPatternLightUp = 14, + // + // Summary: + // Grid. + xlPatternGrid = 15, + // + // Summary: + // Criss-cross lines. + xlPatternCrissCross = 16, + // + // Summary: + // 16% gray. + xlPatternGray16 = 17, + // + // Summary: + // 8% gray. + xlPatternGray8 = 18, + // + xlPatternLinearGradient = 4000, + // + xlPatternRectangularGradient = 4001 + } + + //======================================================================= + // + // Summary: + // Specifies the color of a selected feature such as border, font, or fill. + public enum XlColorIndex + { + // + // Summary: + // No color. + xlColorIndexNone = -4142, + // + // Summary: + // Automatic color. + xlColorIndexAutomatic = -4105 + } + + //======================================================================= + // + // Summary: + // Specifies the RGB color. + public enum XlRgbColor + { + // + // Summary: + // Black + rgbBlack = 0, + // + // Summary: + // Maroon + rgbMaroon = 128, + // + // Summary: + // Dark Red + rgbDarkRed = 139, + // + // Summary: + // Red + rgbRed = 255, + // + // Summary: + // Orange Red + rgbOrangeRed = 17919, + // + // Summary: + // Dark Green + rgbDarkGreen = 25600, + // + // Summary: + // Green + rgbGreen = 32768, + // + // Summary: + // Olive + rgbOlive = 32896, + // + // Summary: + // Dark Orange + rgbDarkOrange = 36095, + // + // Summary: + // Orange + rgbOrange = 42495, + // + // Summary: + // Gold + rgbGold = 55295, + // + // Summary: + // Lawn Green + rgbLawnGreen = 64636, + // + // Summary: + // Lime + rgbLime = 65280, + // + // Summary: + // Chartreuse + rgbChartreuse = 65407, + // + // Summary: + // Yellow + rgbYellow = 65535, + // + // Summary: + // Dark Goldenrod + rgbDarkGoldenrod = 755384, + // + // Summary: + // Goldenrod + rgbGoldenrod = 2139610, + // + // Summary: + // Fire Brick + rgbFireBrick = 2237106, + // + // Summary: + // Forest Green + rgbForestGreen = 2263842, + // + // Summary: + // Olive Drab + rgbOliveDrab = 2330219, + // + // Summary: + // Brown + rgbBrown = 2763429, + // + // Summary: + // Sienna + rgbSienna = 2970272, + // + // Summary: + // Dark Olive Green + rgbDarkOliveGreen = 3107669, + // + // Summary: + // Green Yellow + rgbGreenYellow = 3145645, + // + // Summary: + // Lime Green + rgbLimeGreen = 3329330, + // + // Summary: + // Yellow Green + rgbYellowGreen = 3329434, + // + // Summary: + // Crimson + rgbCrimson = 3937500, + // + // Summary: + // Peru + rgbPeru = 4163021, + // + // Summary: + // Tomato + rgbTomato = 4678655, + // + // Summary: + // Dark Slate Gray + rgbDarkSlateGray = 5197615, + // + // Summary: + // Dark Slate Grey + rgbDarkSlateGrey = 5197615, + // + // Summary: + // Coral + rgbCoral = 5275647, + // + // Summary: + // Sea Green + rgbSeaGreen = 5737262, + // + // Summary: + // Indian Red + rgbIndianRed = 6053069, + // + // Summary: + // Sandy Brown + rgbSandyBrown = 6333684, + // + // Summary: + // Dim Gray + rgbDimGray = 6908265, + // + // Summary: + // Dim Grey + rgbDimGrey = 6908265, + // + // Summary: + // Dark Khaki + rgbDarkKhaki = 7059389, + // + // Summary: + // Pale Goldenrod + rgbPaleGoldenrod = 7071982, + // + // Summary: + // Midnight Blue + rgbMidnightBlue = 7346457, + // + // Summary: + // Medium Sea Green + rgbMediumSeaGreen = 7451452, + // + // Summary: + // Salmon + rgbSalmon = 7504122, + // + // Summary: + // Dark Salmon + rgbDarkSalmon = 8034025, + // + // Summary: + // Light Salmon + rgbLightSalmon = 8036607, + // + // Summary: + // Spring Green + rgbSpringGreen = 8388352, + // + // Summary: + // Navy + rgbNavy = 8388608, + // + // Summary: + // Navy Blue + rgbNavyBlue = 8388608, + // + // Summary: + // Purple + rgbPurple = 8388736, + // + // Summary: + // Teal + rgbTeal = 8421376, + // + // Summary: + // Gray + rgbGray = 8421504, + // + // Summary: + // Grey + rgbGrey = 8421504, + // + // Summary: + // Light Coral + rgbLightCoral = 8421616, + // + // Summary: + // Indigo + rgbIndigo = 8519755, + // + // Summary: + // Medium Violet Red + rgbMediumVioletRed = 8721863, + // + // Summary: + // Burly Wood + rgbBurlyWood = 8894686, + // + // Summary: + // Dark Blue + rgbDarkBlue = 9109504, + // + // Summary: + // Dark Magenta + rgbDarkMagenta = 9109643, + // + // Summary: + // Dark Slate Blue + rgbDarkSlateBlue = 9125192, + // + // Summary: + // Dark Cyan + rgbDarkCyan = 9145088, + // + // Summary: + // Light Cyan + rgbLightCyan = 9145088, + // + // Summary: + // Tan + rgbTan = 9221330, + // + // Summary: + // Khaki + rgbKhaki = 9234160, + // + // Summary: + // Rosy Brown + rgbRosyBrown = 9408444, + // + // Summary: + // Dark Sea Green + rgbDarkSeaGreen = 9419919, + // + // Summary: + // Slate Gray + rgbSlateGray = 9470064, + // + rgbSlateGrey = 9470064, + // + // Summary: + // Light Green + rgbLightGreen = 9498256, + // + // Summary: + // Deep Pink + rgbDeepPink = 9639167, + // + // Summary: + // Pale Violet Red + rgbPaleVioletRed = 9662683, + // + // Summary: + // Pale Green + rgbPaleGreen = 10025880, + // + // Summary: + // Light Slate Gray + rgbLightSlateGray = 10061943, + // + rgbLightSlateGrey = 10061943, + // + // Summary: + // Medium Spring Green + rgbMediumSpringGreen = 10156544, + // + // Summary: + // Cadet Blue + rgbCadetBlue = 10526303, + // + // Summary: + // Dark Gray + rgbDarkGray = 11119017, + // + // Summary: + // Dark Grey + rgbDarkGrey = 11119017, + // + // Summary: + // Light Sea Green + rgbLightSeaGreen = 11186720, + // + // Summary: + // Medium Aquamarine + rgbMediumAquamarine = 11206502, + // + // Summary: + // Navajo White + rgbNavajoWhite = 11394815, + // + // Summary: + // Wheat + rgbWheat = 11788021, + // + // Summary: + // Hot Pink + rgbHotPink = 11823615, + // + // Summary: + // Steel Blue + rgbSteelBlue = 11829830, + // + // Summary: + // Moccasin + rgbMoccasin = 11920639, + // + // Summary: + // Peach Puff + rgbPeachPuff = 12180223, + // + // Summary: + // Silver + rgbSilver = 12632256, + // + // Summary: + // Light Pink + rgbLightPink = 12695295, + // + // Summary: + // Bisque + rgbBisque = 12903679, + // + // Summary: + // Pink + rgbPink = 13353215, + // + // Summary: + // Dark Orchid + rgbDarkOrchid = 13382297, + // + // Summary: + // Medium Turquoise + rgbMediumTurquoise = 13422920, + // + // Summary: + // Medium Blue + rgbMediumBlue = 13434880, + // + // Summary: + // Slate Blue + rgbSlateBlue = 13458026, + // + // Summary: + // Blanched Almond + rgbBlanchedAlmond = 13495295, + // + // Summary: + // Lemon Chiffon + rgbLemonChiffon = 13499135, + // + // Summary: + // Turquoise + rgbTurquoise = 13688896, + // + // Summary: + // Dark Turquoise + rgbDarkTurquoise = 13749760, + // + // Summary: + // LightGoldenrodYellow + rgbLightGoldenrodYellow = 13826810, + // + // Summary: + // Dark Violet + rgbDarkViolet = 13828244, + // + // Summary: + // Medium Orchid + rgbMediumOrchid = 13850042, + // + // Summary: + // Light Gray + rgbLightGray = 13882323, + // + // Summary: + // Light Grey + rgbLightGrey = 13882323, + // + // Summary: + // Aquamarine + rgbAquamarine = 13959039, + // + // Summary: + // Papaya Whip + rgbPapayaWhip = 14020607, + // + // Summary: + // Orchid + rgbOrchid = 14053594, + // + // Summary: + // Antique White + rgbAntiqueWhite = 14150650, + // + // Summary: + // Thistle + rgbThistle = 14204888, + // + // Summary: + // Medium Purple + rgbMediumPurple = 14381203, + // + // Summary: + // Gainsboro + rgbGainsboro = 14474460, + // + // Summary: + // Beige + rgbBeige = 14480885, + // + // Summary: + // Cornsilk + rgbCornsilk = 14481663, + // + // Summary: + // Plum + rgbPlum = 14524637, + // + // Summary: + // Light Steel Blue + rgbLightSteelBlue = 14599344, + // + // Summary: + // Light Yellow + rgbLightYellow = 14745599, + // + // Summary: + // Royal Blue + rgbRoyalBlue = 14772545, + // + // Summary: + // Misty Rose + rgbMistyRose = 14804223, + // + // Summary: + // Blue Violet + rgbBlueViolet = 14822282, + // + // Summary: + // Light Blue + rgbLightBlue = 15128749, + // + // Summary: + // Powder Blue + rgbPowderBlue = 15130800, + // + // Summary: + // Linen + rgbLinen = 15134970, + // + // Summary: + // Old Lace + rgbOldLace = 15136253, + // + // Summary: + // Sky Blue + rgbSkyBlue = 15453831, + // + // Summary: + // Cornflower Blue + rgbCornflowerBlue = 15570276, + // + // Summary: + // Medium Slate Blue + rgbMediumSlateBlue = 15624315, + // + // Summary: + // Violet + rgbViolet = 15631086, + // + // Summary: + // Pale Turquoise + rgbPaleTurquoise = 15658671, + // + // Summary: + // Seashell + rgbSeashell = 15660543, + // + // Summary: + // Floral White + rgbFloralWhite = 15792895, + // + // Summary: + // Honeydew + rgbHoneydew = 15794160, + // + // Summary: + // Ivory + rgbIvory = 15794175, + // + // Summary: + // Lavender Blush + rgbLavenderBlush = 16118015, + // + // Summary: + // White Smoke + rgbWhiteSmoke = 16119285, + // + // Summary: + // Light Sky Blue + rgbLightSkyBlue = 16436871, + // + // Summary: + // Lavender + rgbLavender = 16443110, + // + // Summary: + // Snow + rgbSnow = 16448255, + // + // Summary: + // Mint Cream + rgbMintCream = 16449525, + // + // Summary: + // Blue + rgbBlue = 16711680, + // + // Summary: + // Fuchsia + rgbFuchsia = 16711935, + // + // Summary: + // Dodger Blue + rgbDodgerBlue = 16748574, + // + // Summary: + // Deep Sky Blue + rgbDeepSkyBlue = 16760576, + // + // Summary: + // Alice Blue + rgbAliceBlue = 16775408, + // + // Summary: + // Ghost White + rgbGhostWhite = 16775416, + // + // Summary: + // Aqua + rgbAqua = 16776960, + // + // Summary: + // Azure + rgbAzure = 16777200, + // + // Summary: + // White + rgbWhite = 16777215 + } + + //======================================================================= +} diff --git a/SacsStandardData/Data/Excel/SaMsSpreadsheet-Dfn.cs b/SacsStandardData/Data/Excel/SaMsSpreadsheet-Dfn.cs new file mode 100644 index 0000000..0fd0b34 --- /dev/null +++ b/SacsStandardData/Data/Excel/SaMsSpreadsheet-Dfn.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Sarand.Net.Standard.Data.Excel +{ + //======================================================================= + // Definitions. + public enum SaExcelLogicalUnit + { + Point, + Pixel, + Cm, + Inch, + //CharWidth, // Not supported. + }; + //======================================================================= + /// Spreadsheet file format. + /// Ref. Microsoft.Office.Interop.Excel.XlFileFormat + public enum SaXlFileFormat + { + Default = 0, + /// Without macro's in 2007-2013 [xlsx]. Value: 51. + OpenXMLWorkbook = XlFileFormat.xlOpenXMLWorkbook, + /// With or without macro's in 2007-2013 [xlsm]. Value: 52. + OpenXMLWorkbookMacroEnabled = XlFileFormat.xlOpenXMLWorkbookMacroEnabled, + /// Excel Binary Workbook in 2007-2013 with or without macro's [xlsb]. Value: 50. + Excel12 = XlFileFormat.xlExcel12, + /// 97-2003 format in Excel 2007-2013 [xls]. Value: 56. + Excel8 = XlFileFormat.xlExcel8, + /// CSV format. Value: 6. + CSV = XlFileFormat.xlCSV, + }; + /// + /// Specifies the page orientation when the worksheet is printed. + /// Ref. Microsoft.Office.Interop.Excel.XlPageOrientation + /// + public enum SaXlPageOrientation + { + NotSpecified = int.MinValue, + xlPortrait = XlPageOrientation.xlPortrait, + xlLandscape = XlPageOrientation.xlLandscape + } + /// + /// Specifies the weight of the border around a range. + /// Ref. Microsoft.Office.Interop.Excel.XlBorderWeight + /// + public enum SaXlBorderWeight + { + NotSpecified = int.MinValue, + Hairline = XlBorderWeight.xlHairline, + Thin = XlBorderWeight.xlThin, + Medium = XlBorderWeight.xlMedium, + Thick = XlBorderWeight.xlThick + } + /// + /// Specifies the line style for the border. + /// Ref. Microsoft.Office.Interop.Excel.XlLineStyle + /// + public enum SaXlLineStyle + { + NotSpecified = int.MinValue, + None = XlLineStyle.xlLineStyleNone, + Double = XlLineStyle.xlDouble, + Dot = XlLineStyle.xlDot, + Dash = XlLineStyle.xlDash, + Continuous = XlLineStyle.xlContinuous, + DashDot = XlLineStyle.xlDashDot, + DashDotDot = XlLineStyle.xlDashDotDot, + SlantDashDot = XlLineStyle.xlSlantDashDot, + } + /// + /// Specifies the interior pattern of a chart or interior object. + /// Ref. Microsoft.Office.Interop.Excel.XlPattern + /// + public enum SaXlPattern + { + NotSpecified = int.MinValue, + /// No pattern. + None = XlPattern.xlPatternNone, + /// Excel controls the pattern. + Automatic = XlPattern.xlPatternAutomatic, + /// 8% gray. + Gray8 = XlPattern.xlPatternGray8, + /// 16% gray. + Gray16 = XlPattern.xlPatternGray16, + /// 25% gray. + Gray25 = XlPattern.xlPatternGray25, + /// 50% gray. + Gray50 = XlPattern.xlPatternGray50, + /// 75% gray. + Gray75 = XlPattern.xlPatternGray75, + /// 75% dark moiré. + SemiGray75 = XlPattern.xlPatternSemiGray75, + /// Solid color. + Solid = XlPattern.xlPatternSolid, + /// Dark vertical bars. + Vertical = XlPattern.xlPatternVertical, + /// Dark horizontal lines. + Horizontal = XlPattern.xlPatternHorizontal, + /// Dark diagonal lines running from the lower left to the upper right. + Up = XlPattern.xlPatternUp, + /// Dark diagonal lines running from the upper left to the lower right. + Down = XlPattern.xlPatternDown, + /// Checkerboard. + Checker = XlPattern.xlPatternChecker, + /// Light horizontal lines. + LightHorizontal = XlPattern.xlPatternLightHorizontal, + /// Light vertical bars. + LightVertical = XlPattern.xlPatternLightVertical, + /// Light diagonal lines running from the upper left to the lower right. + LightDown = XlPattern.xlPatternLightDown, + /// Light diagonal lines running from the lower left to the upper right. + LightUp = XlPattern.xlPatternLightUp, + /// Grid. + Grid = XlPattern.xlPatternGrid, + /// Criss-cross lines. + CrissCross = XlPattern.xlPatternCrissCross, + LinearGradient = XlPattern.xlPatternLinearGradient, + RectangularGradient = XlPattern.xlPatternRectangularGradient + } + /// + /// Colour index. + /// Ref. Microsoft.Office.Interop.Excel.XlColorIndex. + /// + public enum SaXlColourIndex + { + NotSpecified = int.MinValue, + /// No color. -4142, &HFFFFEFD2. + None = XlColorIndex.xlColorIndexNone, + /// Automatic color. -4105, &HFFFFEFF7. + Automatic = XlColorIndex.xlColorIndexAutomatic, + Black = 1, + White = 2, + Red = 3, + BrightGreen = 4, + Blue = 5, + Yellow = 6, + Pink = 7, + Magenta = 7, + Turqoise = 8, + Cyan = 8, + DarkRed = 9, + Green = 10, + DarkBlue = 11, + DarkYellow = 12, + Violet = 13, + Teal = 14, + Gray25 = 15, + Gray50 = 16, + SkyBlue = 33, + LightTurqoise = 34, + LightGreen = 35, + LightYellow = 36, + PaleBlue = 37, + Rose = 38, + Lavendar = 39, + Tan = 40, + LightBlue = 41, + Aqua = 42, + Lime = 43, + Gold = 44, + LightOrange = 45, + Orange = 46, + BlueGray = 47, + Gray40 = 48, + DarkTeal = 49, + SeaGreen = 50, + DarkGreen = 51, + OliveGreen = 52, + Brown = 53, + Plum = 54, + Indigo = 55, + Gray80 = 56, + }; + /// + /// RGB colour value. + /// Ref. Microsoft.Office.Interop.Excel.XlRgbColor. + /// + public enum SaXlRgbColor + { + NotSpecified = int.MinValue, + Red = XlRgbColor.rgbRed, + } + /// + /// Specifies the type of underline applied to a font. + /// Ref. Microsoft.Office.Interop.Excel.XlUnderlineStyle + /// + public enum SaXlUnderlineStyle + { + /// No underlining. + None = XlUnderlineStyle.xlUnderlineStyleNone, + /// Double thick underline. + Double = XlUnderlineStyle.xlUnderlineStyleDouble, + /// Single underlining. + Single = XlUnderlineStyle.xlUnderlineStyleSingle, + /// Single accounting - Not supported. + SingleAccounting = XlUnderlineStyle.xlUnderlineStyleSingleAccounting, + /// Double accounting - Two thin underlines placed close together. + DoubleAccounting = XlUnderlineStyle.xlUnderlineStyleDoubleAccounting + } + + //======================================================================= +} diff --git a/SacsStandardData/Data/Excel/SaMsSpreadsheet.cs b/SacsStandardData/Data/Excel/SaMsSpreadsheet.cs new file mode 100644 index 0000000..84d7090 --- /dev/null +++ b/SacsStandardData/Data/Excel/SaMsSpreadsheet.cs @@ -0,0 +1,569 @@ +using System; +using System.Collections.Generic; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Utils; + +namespace Sarand.Net.Standard.Data.Excel +{ + //======================================================================= + // Some Excel enumerated values are replaced with local integers or + // equivalent enum to avoid errors related to: + // "Cannot be used across assembly boundaries because it has a + // generic type parameter that is an embedded interop type." + // eg. SaMsExcelItemAttr.HorizontalAlignment: short instead of XlHAlign. + //======================================================================= + public class SaMsExcelRange + { + public uint ColFrom { get; set; } = 0; + public uint ColTo { get; set; } = 0; + public uint RowFrom { get; set; } = 0; + public uint RowTo { get; set; } = 0; + public SaMsExcelRange() { } + public SaMsExcelRange(uint colPos, uint rowPos) + { + ColFrom = colPos; + ColTo = colPos; + RowFrom = rowPos; + RowTo = rowPos; + } + public SaMsExcelRange(uint colPosFrom, uint rowPosFrom, uint colPosTo, uint rowPosTo) + { + ColFrom = colPosFrom; + ColTo = colPosTo; + RowFrom = rowPosFrom; + RowTo = rowPosTo; + } + } + //======================================================================= + public class SaMsExcelPageSetup_Config + { + public SaMsExcelPageSetup_Config() + { + } + /// Orientation: xlPortrait (1) or xlLandscape (2). Default: Not specified (ignore) + public SaXlPageOrientation Orientation { get; set; } = SaXlPageOrientation.NotSpecified; + /// Logical unit. Default: Point. + public SaExcelLogicalUnit Unit { get; set; } = SaExcelLogicalUnit.Point; + // Headers and footers. + // NB Font & size and page no and total pages can be encoded as: '&"Batang,Regular"&14Page &P of &N' + public String HeaderLeft { get; set; } = ""; + public String HeaderCenter { get; set; } = ""; + public String HeaderRight { get; set; } = ""; + public String FooterLeft { get; set; } = ""; + public String FooterCenter { get; set; } = ""; + public String FooterRight { get; set; } = ""; + // Margins. + // Negative values leave current value (default=-1.0). + public double MarginLeft { get; set; } = -1.0; + public double MarginRight { get; set; } = -1.0; + public double MarginTop { get; set; } = -1.0; + public double MarginBottom { get; set; } = -1.0; + public double MarginHeader { get; set; } = -1.0; + public double MarginFooter { get; set; } = -1.0; + // Negative values to leave current value, zero to clear (default=-1). + public int PrintTitleRowFrom { get; set; } = -1; + public int PrintTitleRowTo { get; set; } = -1; + public int PrintTitleColFrom { get; set; } = -1; + public int PrintTitleColTo { get; set; } = -1; + // Zoom or 'fit to' pages. + /// Zoom: 40 = 40%, default: -1. + public int Zoom { get; set; } = -1; + /// Fit to pages - Tall. 1 = 1 page tall, default = -1. [ignored if zoom > 0] + public int FitToPagesTall { get; set; } = -1; + /// Fit to pages - Wide. 1 = 1 page wide, default = -1. [ignored if zoom > 0] + public int FitToPagesWide { get; set; } = -1; + } + //======================================================================= + public class SaMsExcelColumnHeading_Config + { + public double ColumnWidthPixelsPerCm { get; set; } = 43.0; // Between 10 and 100 + public uint FirstHeadingRow { get; set; } = 1; // Must be > 0 + public uint FirstHeadingColumn { get; set; } = 1; // Must be > 0 + public uint FreezeColumn { get; set; } = 0; // 0 = don't freeze + public short HeadingFontSize { get; set; } = 9; + public bool HeadingTextBold { get; set; } = true; + public bool HeadingTextWrap { get; set; } = true; + /// Cell font colour index, ref. XlColorIndex + public SaXlColourIndex InteriorColourIndex { get; set; } = SaXlColourIndex.NotSpecified; + /// Cell RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value. + public int? InteriorColour { get; set; } = null; + public SaXlBorderWeight BorderWeight { get; set; } = SaXlBorderWeight.NotSpecified; + public bool SetColumnWidths { get; set; } = true; + public bool SetColumnAlignment { get; set; } = true; + public bool SetColumnDataTypeFormat { get; set; } = true; // '@' for strings, '#,##0.00' for numeric depending on thousands/decimals + public String CellFormatDate { get; set; } = "d-mmm-yy"; + public String CellFormatTime { get; set; } = "hh:mm"; + public String CellFormatDateTimeDelim { get; set; } = " "; + } + //======================================================================= + public class SaMsExcelImage_Config + { + public SaMsExcelImage_Config() { } + public String ImagePath { get; set; } = ""; + /// Column to insert image. Default: 0 (current position). + public uint ColPos { get; set; } = 0; + /// Row to insert image. Default: 0 (current position). + public uint RowPos { get; set; } = 0; + /// Image dimension units. Default: Point. + public SaExcelLogicalUnit Unit { get; set; } = SaExcelLogicalUnit.Point; + public double TargetWidth { get; set; } = 0.0; + public double TargetHeight { get; set; } = 0.0; + public double MaxWidth { get; set; } = 0.0; + public double MaxHeight { get; set; } = 0.0; + }; + //======================================================================= + public class SaMsExcelBorderAttr + { + public SaMsExcelBorderAttr(XlBordersIndex index) + { + Index = index; + } + public bool IsSpecified + { + get + { + // Any attributes specified. + if (Weight != SaXlBorderWeight.NotSpecified) return true; + if (LineStyle != SaXlLineStyle.NotSpecified) return true; + if (ColorIndex != SaXlColourIndex.NotSpecified) return true; + if (Color != null) return true; + return false; + } + } + /// Border position. XlBordersIndex.xlEdgeLeft etc + public XlBordersIndex Index { get; } + /// Border thickness. XlBorderWeight.xlThin, XlBorderWeight.xlMedium etc. + public SaXlBorderWeight Weight { get; set; } = SaXlBorderWeight.NotSpecified; + /// Border line style. XlLineStyle.xlNone, XlLineStyle.xlContinuous, XlLineStyle.xlDash etc. + public SaXlLineStyle LineStyle { get; set; } = SaXlLineStyle.NotSpecified; + /// Border colour index, re. XlColorIndex. Black = 1 etc. + public SaXlColourIndex ColorIndex { get; set; } = SaXlColourIndex.NotSpecified; + /// Border RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value. + public int? Color { get; set; } = null; + } + //======================================================================= + public class SaMsExcelFontAttr + { + /// Font name. Arial etc. + public String FontName { get; set; } = String.Empty; + /// Font style. Regular etc. + public String FontStyle { get; set; } = String.Empty; + public short? FontSize { get; set; } = null; + /// Font colour index, ref. XlColorIndex. + public SaXlColourIndex FontColourIndex { get; set; } = SaXlColourIndex.NotSpecified; + /// Font RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value. + public int? FontColor { get; set; } = null; + public bool? Bold { get; set; } = null; + public bool? Strikethrough { get; set; } = null; + public bool? Superscript { get; set; } = null; + public bool? Subscript { get; set; } = null; + public bool? OutlineFont { get; set; } = null; + public bool? Shadow { get; set; } = null; + public SaXlUnderlineStyle? Underline { get; set; } = null; + } + //======================================================================= + public class SaMsExcelItemAttr : SaMsExcelFontAttr + { + // Item attributes. + // Attributes that are changed from their default (generally null) are set against the specified range. + /// Cell data format. "@"=Text etc. + public String NumberFormat { get; set; } = String.Empty; + /// Cell horizontal alignment. XlHAlign.xlHAlignLeft, xlHAlignCenter, xlHAlignRight etc. + public short? HorizontalAlignment { get; set; } = null; + /// Cell indentation. Tabbed - left, right or distributed alignment [0 to 6] + public short? IndentLevel { get; set; } = null; + /// Cell vertical alignment. XlVAlign.xlTop, xlCenter, xlBottom, xlJustify, xlDistributed etc. + public short? VerticalAlignment { get; set; } = null; + /// Whether to allow text to wrap in cells. + public bool? WrapText { get; set; } = null; + /// Whether cells are merged. + public bool? MergeCells { get; set; } = null; + /// Font colour index, ref. XlColorIndex. Black = 1 etc. + public SaXlColourIndex InteriorColourIndex { get; set; } = SaXlColourIndex.NotSpecified; + /// Cell RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value. + public int? InteriorColour { get; set; } = null; + /// Cell pattern, ref. XlPattern. xlSolid etc. + public SaXlPattern InteriorPattern { get; set; } = SaXlPattern.NotSpecified; + /// Cell pattern colour index, ref. XlColorIndex. xlAutomatic etc. + public SaXlColourIndex InteriorPatternColourIndex { get; set; } = SaXlColourIndex.NotSpecified; + /// Cell pattern RBG Colour value, ref. XlRgbColor. Overrides colour index if changed from default value. + public int? InteriorPatternColour { get; set; } = null; + // Borders. + public SaMsExcelBorderAttr BorderLeft { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeLeft); + public SaMsExcelBorderAttr BorderTop { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeTop); + public SaMsExcelBorderAttr BorderRight { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeRight); + public SaMsExcelBorderAttr BorderBottom { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeBottom); + public SaMsExcelBorderAttr BorderInsideVertical { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlInsideVertical); + public SaMsExcelBorderAttr BorderInsideHorizontal { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlInsideHorizontal); + public List Borders + { + get + { + List borders = new List(); + borders.Add(BorderLeft); + borders.Add(BorderTop); + borders.Add(BorderRight); + borders.Add(BorderBottom); + return borders; + } + } + } + //======================================================================= + public abstract class SaMsSpreadsheet : SaErrorStateItem + { + //------------------------------------------------------------------- + // Definitions. + public static int FontSizeMin { get; } = 4; + public static int FontSizeMax { get; } = 48; + public static int NullColour { get; } = 0x4a4d4120; /* AFX_RFX_LONG_PSEUDO_NULL */ + + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + protected SaMsSpreadsheet() + { + } + protected override void Dispose(bool disposing) + { + if (disposing) + { + } + base.Dispose(disposing); + } + + //------------------------------------------------------------------- + // W o r k b o o k + //------------------------------------------------------------------- + public abstract bool IsWorkbookValid(); + public abstract bool CreateWorkbook(); + public abstract bool OpenWorkbook(String filePath); + public abstract bool SaveDocument(String filePath, int fileFormat = (int)SaXlFileFormat.Default /* Default: XlFileFormat.xlOpenXMLWorkbook */, bool bAutomaticallyOverwrite = false); + public abstract bool CloseWorkbook(); + + //------------------------------------------------------------------- + // W o r k s h e e t + //------------------------------------------------------------------- + /// Is the current worksheet valid. + public abstract bool IsWorksheetValid(); + /// Number of worksheets in the workbook. + public abstract uint WorksheetCount { get; } + /// Set the worksheets in the workbook - sheets are added or removed to match the value. + public abstract bool SetWorksheetCount(int worksheetCount); + /// Add a worksheet to the workbook. + public abstract bool AddWorksheet(String name); + /// Remove the nth worksheet - position from 1. + public abstract bool RemoveWorksheet(uint worksheetPos); + /// Open the nth worksheet - position from 1. + public abstract bool OpenWorksheet(uint worksheetPos); + /// Get the position of the current worksheet. 0 = not open. + public abstract uint WorksheetPos { get; } + /// Get the name of the current worksheet. + public abstract String WorksheetName { get; set; } + /// Set the default attributes for the entire worksheet + public abstract bool SetWorksheetAttr(SaMsExcelItemAttr attr); + /// Close the current worksheet. + public abstract bool CloseWorksheet(); + // Worksheet Page Setup. + /// Configure the Page Setup properties. + public abstract bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig); + /// Configure a page break at the specified cell. + public abstract bool SetPageBreak(uint colPos, uint rowPos); + + //------------------------------------------------------------------- + // C o l u m n s + //------------------------------------------------------------------- + public abstract uint GetActiveColPos(); + public abstract double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point); + public abstract bool SetColWidth(uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point); + + //------------------------------------------------------------------- + // R o w s + //------------------------------------------------------------------- + public abstract uint GetActiveRowPos(); + public abstract List GetRowDataValues(uint rowPos, int maxColumns = 0); + public abstract double GetRowHeight(uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point); + public abstract bool SetRowHeight(uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point); + + //------------------------------------------------------------------- + // C e l l s + //------------------------------------------------------------------- + public abstract void SetActiveCell(uint colPos, uint rowPos); + public abstract String GetCellFormula(uint colPos, uint rowPos); + public abstract DataValue GetCellDataValue(uint colPos, uint rowPos); + public abstract bool SetCellFormula(uint colPos, uint rowPos, String value); + public abstract bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr); + public abstract bool SetRowFormulas(uint colStart, uint row, List values); + public abstract bool SetRangeFormulas(SaMsExcelRange range, List values); + + //------------------------------------------------------------------- + // Populate headings. + public bool SetColumnHeadings(List columns, SaMsExcelColumnHeading_Config config) + { + ClearErrorState(); + double columnWidthPixelsPerCm = Math.Min(100.0, Math.Max(10.0, config.ColumnWidthPixelsPerCm)); + uint firstHeadingRow = (uint)Math.Max(1, config.FirstHeadingRow); + try + { + // Populate default heading cell attributes. + SaMsExcelItemAttr attrHdrDefault = new SaMsExcelItemAttr(); + attrHdrDefault.Bold = config.HeadingTextBold; + attrHdrDefault.FontSize = (short)Math.Min(80, Math.Max(2, (int)config.HeadingFontSize)); + attrHdrDefault.InteriorColourIndex = config.InteriorColourIndex; + if (config.InteriorColour != null) + attrHdrDefault.InteriorColour = config.InteriorColour; + if (config.BorderWeight != SaXlBorderWeight.NotSpecified) + { + attrHdrDefault.BorderLeft.Weight = config.BorderWeight; + attrHdrDefault.BorderTop.Weight = config.BorderWeight; + attrHdrDefault.BorderRight.Weight = config.BorderWeight; + attrHdrDefault.BorderBottom.Weight = config.BorderWeight; + attrHdrDefault.BorderInsideVertical.Weight = config.BorderWeight; + } + SaMsExcelRange rangeHeadings = new SaMsExcelRange(config.FirstHeadingColumn, firstHeadingRow, (uint)(config.FirstHeadingColumn + columns.Count - 1), firstHeadingRow); + SetRangeAttr(rangeHeadings, attrHdrDefault); + + // Set default column attributes. + bool defaultColumnAttributesPopulated = false; + SaMsExcelItemAttr attrColDefault = new SaMsExcelItemAttr(); + if (config.SetColumnAlignment) + { + attrColDefault.HorizontalAlignment = (short)XlHAlign.xlHAlignLeft; + defaultColumnAttributesPopulated = true; + } + if (config.SetColumnDataTypeFormat) + { + attrColDefault.NumberFormat = "@"; // '@' = 'Text' format. + defaultColumnAttributesPopulated = true; + } + if (defaultColumnAttributesPopulated) + { + SaMsExcelRange rangeColumns = new SaMsExcelRange(config.FirstHeadingColumn, 0, (uint)(config.FirstHeadingColumn + columns.Count - 1), 0); + SetRangeAttr(rangeColumns, attrColDefault); + } + + // Populate column headings and specific styles. + List values = new List(); + for (int columnIdx = 0; columnIdx < columns.Count; columnIdx++) + { + ColumnDfn column = columns[columnIdx]; + uint col = (uint)(Math.Max(1, config.FirstHeadingColumn) + columnIdx); + SaMsExcelRange range = new SaMsExcelRange(col, firstHeadingRow); + + // Specific heading cell attributes - none supported as yet. + bool headingCellHasSpecificAttr = false; + SaMsExcelItemAttr attrHdr = new SaMsExcelItemAttr(); + if (headingCellHasSpecificAttr) + SetRangeAttr(range, attrHdr); + + // Column width and caption: + if (config.SetColumnWidths) SetColWidth(col, column.Width / columnWidthPixelsPerCm, SaExcelLogicalUnit.Cm); + values.Add(column.Caption); + + // Column attributes: + bool columnHasSpecificAttributes = false; + SaMsExcelItemAttr attrCol = new SaMsExcelItemAttr(); + if (config.SetColumnAlignment && column.Alignment != ColumnAlignment.Left && column.Alignment != ColumnAlignment.Default) + { + columnHasSpecificAttributes = true; + switch (column.Alignment) + { + case ColumnAlignment.Center: attrCol.HorizontalAlignment = (short)XlHAlign.xlHAlignCenter; break; + case ColumnAlignment.Right: attrCol.HorizontalAlignment = (short)XlHAlign.xlHAlignRight; break; + } + } + if (config.SetColumnDataTypeFormat && column.DataType != DataValue.DataType.String) + { + columnHasSpecificAttributes = true; + if (column.DataType == DataValue.DataType.Long || column.DataType == DataValue.DataType.Double || column.DataType == DataValue.DataType.Decimal) + { + // Numeric format: "#,##0.00" + String numberFormat = "0"; + if (column.NumThousands != '\0') + { + numberFormat = "###" + numberFormat; + numberFormat = numberFormat.Insert(1, column.NumThousands.ToString()); // Ends up as '#,##0'. + } + if ((column.DataType == DataValue.DataType.Double || column.DataType == DataValue.DataType.Decimal) && column.NumDecimals > 0) + numberFormat += "." + "0".PadRight(column.NumDecimals, '0'); + attrCol.NumberFormat = numberFormat + ";[Red]-" + numberFormat; + } + else if (column.DataType == DataValue.DataType.Date) attrCol.NumberFormat = config.CellFormatDate; + else if (column.DataType == DataValue.DataType.Time) attrCol.NumberFormat = config.CellFormatTime; + else if (column.DataType == DataValue.DataType.DateTime) attrCol.NumberFormat = config.CellFormatDate + config.CellFormatDateTimeDelim + config.CellFormatTime; + } + if (columnHasSpecificAttributes) + SetRangeAttr(new SaMsExcelRange(col, 0), attrCol); + // Freeze the window below if a colmn has been specified: + if (config.FreezeColumn > 0) FreezePanes(config.FreezeColumn, firstHeadingRow + 1); + } + // Populate header captions. + SetRowFormulas(config.FirstHeadingColumn, firstHeadingRow, values); + // Set header row to wrap text: + if (config.HeadingTextWrap) + { + SaMsExcelItemAttr attrRow = new SaMsExcelItemAttr(); + attrRow.WrapText = true; + SetRangeAttr(new SaMsExcelRange(0, firstHeadingRow), attrRow); + // Auto fit the header row (set height to fit text): + AutoFit(new SaMsExcelRange(0, firstHeadingRow)); + } + } + catch (Exception exc) { HandleException("SetColumnHeadings", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // Cell attributes. + public abstract bool SetRangeAttr(SaMsExcelRange range, SaMsExcelItemAttr attr); + + //------------------------------------------------------------------- + // Add image to sheet. + public abstract bool InsertImage(SaMsExcelImage_Config imageConfig); + + //------------------------------------------------------------------- + public abstract bool FreezePanes(uint colPos, uint rowPos); + + //------------------------------------------------------------------- + public abstract bool AutoFit(SaMsExcelRange range); + + //------------------------------------------------------------------- + public abstract bool SelectRange(SaMsExcelRange range); + + //------------------------------------------------------------------- + // Utilities. + public static String GetRangeId(SaMsExcelRange range, bool fixedCols = false, bool fixedRows = false) + { + // Not fixed: "A9:AB34" + // Fixed cols: "$A9:$AB34" + // Fixed rows: "A$9:AB$34" + // Fixed: "$A$9:$AB$34" + return (fixedCols ? "$" : "") + GetColumnPrefix(range.ColFrom) + (fixedRows ? "$" : "") + GetRowSuffix(range.RowFrom) + ":" + (fixedCols ? "$" : "") + GetColumnPrefix(range.ColTo) + (fixedRows ? "$" : "") + GetRowSuffix(range.RowTo); + } + public static String GetColumnPrefix(uint colPos) + { + // 1=A,2=B,3=C...26=Z,27=AA,28=AB etc + uint dividend = colPos; + string columnName = String.Empty; + uint modulo = 0; + while (dividend > 0) + { + modulo = (dividend - 1) % 26; + columnName = Convert.ToChar(65 + modulo).ToString() + columnName; + dividend = (uint)((dividend - modulo) / 26); + } + return columnName; + } + public static int GetIndexForCol(String column) + { + // A=1,B=2,C=3...Z=26,AA=27 etc + int col = (column[0] - 'A'); + if (column.Length > 1) + col = (column[1] * 26) + column[0]; + return col; + } + public static String GetColumnId(uint colPos) + { + // To reference entire column: A:A,B:A,C:A...Z:Z,AA:AA etc + return GetColumnPrefix(colPos) + ":" + GetColumnPrefix(colPos); + } + public static String GetRowSuffix(uint rowPos) + { + // 1,2,3...26,27,28 etc + return (rowPos > 0 ? rowPos.ToString() : ""); + } + public static String GetRowId(uint rowPos) + { + // To reference entire row: 1:1,2:2,3:3 etc + return GetRowSuffix(rowPos) + ":" + GetRowSuffix(rowPos); + } + public static String GetCellId(uint colPos, uint rowPos) + { + return GetColumnPrefix(colPos) + GetRowSuffix(rowPos); + } + public static DateTime ExtractDate(String value) + { + DateTime date = DateTime.MinValue; + // TODO SaMsSpreadsheet.ExtractDate + return date; + } + + //------------------------------------------------------------------- + // L e n g t h U n i t C o n v e r s i o n + //------------------------------------------------------------------- + // Points + // - 72 per inch + // EMU - English Metric Unit + // - 914400 EMUs per inch + // - EMU = inch * 914400 + // - EMU = pixel * 914400 / 96 (assuming 96 dpi) + //------------------------------------------------------------------- + public static double PointsPerInch { get; } = 72; + public static double PixelsPerInch { get; } = 96; + public static double CmsPerInch { get; } = 2.54f; + public double ConvertLength(double fLength, SaExcelLogicalUnit eUnitFrom, SaExcelLogicalUnit eUnitTo, bool bVertical) + { + // Convert length to points: + double fLengthPoints = fLength; + if (eUnitFrom == SaExcelLogicalUnit.Pixel) fLengthPoints = PixelsToPoints(fLength, bVertical); + else if (eUnitFrom == SaExcelLogicalUnit.Cm) fLengthPoints = CmsToPoints(fLength); + else if (eUnitFrom == SaExcelLogicalUnit.Inch) fLengthPoints = InchesToPoints(fLength); + // Convert points to target units: + double fLengthTarget = fLengthPoints; + if (eUnitTo == SaExcelLogicalUnit.Pixel) fLengthTarget = PointsToPixels(fLengthPoints, bVertical); + else if (eUnitTo == SaExcelLogicalUnit.Cm) fLengthTarget = PointsToCms(fLengthPoints); + else if (eUnitTo == SaExcelLogicalUnit.Inch) fLengthTarget = PointsToInches(fLengthPoints); + return fLengthTarget; + } + public double ToPoints(double fLength, SaExcelLogicalUnit eUnitFrom, bool bVertical) + { + return ConvertLength(fLength, eUnitFrom, SaExcelLogicalUnit.Point, bVertical); + } + public double FromPoints(double fLength, SaExcelLogicalUnit eUnitTo, bool bVertical) + { + return ConvertLength(fLength, SaExcelLogicalUnit.Point, eUnitTo, bVertical); + } + public virtual double PointsToPixels(double points, bool bVertical) + { + // Pixel size depends on monitor resolution. + // REf. https://stackoverflow.com/questions/139655/convert-pixels-to-points + // Assume 96 pixels per inch. + return points * PixelsPerInch / PointsPerInch; + } + public virtual double PointsToCms(double points) + { + return PointsToInches(points) * CmsPerInch; + } + public virtual double PointsToInches(double points) + { + return points / PointsPerInch; + } + public virtual double PixelsToPoints(double pixels, bool bVertical) + { + // Pixel size depends on monitor resolution. + // REf. https://stackoverflow.com/questions/139655/convert-pixels-to-points + // Assume 96 pixels per inch. + return pixels / PixelsPerInch * PointsPerInch; + } + public virtual double CmsToPoints(double cms) + { + return InchesToPoints(cms / CmsPerInch); + } + public virtual double InchesToPoints(double inches) + { + return inches * PointsPerInch; + } + + //------------------------------------------------------------------- + protected void HandleException(String fn, Exception exc) + { + SaLogger.Error(GetType().Name + "." + fn + " " + ExceptionUtil.GetLogMessage(exc)); + SetErrorState("Problems were encountered interfacing to Excel - " + ExceptionUtil.GetErrorStateMessage(exc)); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardData/Data/Excel/SaMsSpreadsheet_Direct.cs b/SacsStandardData/Data/Excel/SaMsSpreadsheet_Direct.cs new file mode 100644 index 0000000..9f9cd38 --- /dev/null +++ b/SacsStandardData/Data/Excel/SaMsSpreadsheet_Direct.cs @@ -0,0 +1,909 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Utils; +using Sarand.Net.Standard.Data.Xml; +using Sarand.Net.Standard.Data.Zip; + +namespace Sarand.Net.Standard.Data.Excel +{ + //======================================================================= + /// Style properties retrieved directly from spreadsheet xml data. + public class SaMsExcelStyle + { + public SaMsExcelStyle () { } + public int NumFmtId { get; set; } + public int FontId { get; set; } + public int FillId { get; set; } + public int BorderId { get; set; } + public int XfId { get; set; } + public bool QuotePrefix { get; set; } + public bool PivotButton { get; set; } + public bool ApplyNumberFormat { get; set; } + public bool ApplyFont { get; set; } + public bool ApplyFill { get; set; } + public bool ApplyBorder { get; set; } + public bool ApplyAlignment { get; set; } + public bool ApplyProtection { get; set; } + public XlHAlign AlignHorizontal { get; set; } + public XlVAlign AlignVertical { get; set; } + public String NumFmtCode { get; set; } = ""; + }; + + //======================================================================= + /// Excel spreadsheet read directly from xml data rather than via COM/Interop. + public class SaMsSpreadsheet_Direct : SaMsSpreadsheet + { + //------------------------------------------------------------------- + // Data members. + internal class Workbook + { + internal SaMsZipArchive WorkbookArchive { get; set; } + internal SaMsXmlDocument WorkbookDoc { get; set; } + internal SaMsXmlDocument SharedStringsDoc { get; set; } + internal SaMsXmlDocument StylesDoc { get; set; } + internal uint WorksheetCount { get; set; } + internal uint ActiveSheetPos { get; set; } + internal bool IsValid () { return (WorkbookDoc != null && WorkbookDoc.GetRootElement() != null); } + } + private Workbook workbook; + private class Worksheet + { + internal uint WorksheetPos { get; set; } + internal uint WorksheetId { get; set; } + internal String WorksheetArchivePath { get; set; } + internal String WorksheetName { get; set; } + internal SaMsXmlDocument WorksheetDoc { get; set; } + internal uint ActiveColPos { get; set; } + internal uint ActiveRowPos { get; set; } + internal class NodesData + { + internal SaMsXmlElement Cols { get; set; } + internal SaMsXmlElement ActiveCol { get; set; } + internal SaMsXmlElement Rows { get; set; } + internal SaMsXmlElement ActiveRow { get; set; } + } + internal NodesData Nodes { get; } = new NodesData(); + bool IsValid () { return (WorksheetDoc != null && WorksheetDoc.GetRootElement() != null); } + + } + private Worksheet worksheet; + + //------------------------------------------------------------------- + // Construction. + public SaMsSpreadsheet_Direct () : base() + { + } + protected override void Dispose (bool disposing) + { + if (disposing) + { + CloseWorkbook(); + } + base.Dispose(disposing); + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // W o r k b o o k + //------------------------------------------------------------------- + public override bool IsWorkbookValid () + { + return (workbook != null && workbook.IsValid()); + } + public override bool CreateWorkbook () + { + CloseWorkbook(); + ClearErrorState(); + + // Create new workbook. + workbook = new Workbook(); + workbook.WorkbookArchive = new SaMsZipArchive(); + workbook.SharedStringsDoc = new SaMsXmlDocument(); + workbook.StylesDoc = new SaMsXmlDocument(); + + return SetErrorState("Creating workbook not supported"); + } + public override bool OpenWorkbook (String filePath) + { + CloseWorkbook(); + ClearErrorState(); + if (!File.Exists(filePath)) + return SetErrorState("Workbook not found"); + List validExtensions = new List() { /*".xls",*/ ".xlsx", ".xlsb", ".zip" }; + String extension = Path.GetExtension(filePath); + if (!validExtensions.ContainsCI(Path.GetExtension(filePath))) + return SetErrorState("Invalid document type (expected xlsx/xlsb)"); + + try + { + // Open workbook document. + workbook = new Workbook(); + workbook.WorkbookArchive = new SaMsZipArchive(); + if (workbook.WorkbookArchive.OpenArchive(filePath)) + { + ExtractWorkbookElementsFromArchive(); + } + else return SetErrorState("Failed to open document: " + workbook.WorkbookArchive.ErrorStateMessage); + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + return !HasErrorState(); + } + public bool OpenWorkbook (byte[] workbookData) + { + CloseWorkbook(); + ClearErrorState(); + try + { + using (MemoryStream workbookStream = new MemoryStream(workbookData)) + { + OpenWorkbook(workbookStream); + } + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + return !HasErrorState(); + } + public bool OpenWorkbook (Stream workbookStream) + { + CloseWorkbook(); + ClearErrorState(); + try + { + // From start of stream. + workbookStream.Seek(0, SeekOrigin.Begin); + // Open workbook document. + workbook = new Workbook(); + workbook.WorkbookArchive = new SaMsZipArchive(); + if (workbook.WorkbookArchive.OpenArchive(workbookStream)) + { + ExtractWorkbookElementsFromArchive(); + } + else return SetErrorState("Failed to open document: " + workbook.WorkbookArchive.ErrorStateMessage); + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + return !HasErrorState(); + } + private bool ExtractWorkbookElementsFromArchive () + { + ClearErrorState(); + try + { + // Extract the workbook data. + using (MemoryStream workbookFile = workbook.WorkbookArchive.ExtractFileToStream("xl/workbook.xml")) + { + if (workbookFile == null) return SetErrorState("Failed to load workbook data"); + workbook.WorkbookDoc = new SaMsXmlDocument(); + if (workbook.WorkbookDoc.LoadXml(workbookFile)) + { + // Workbook successfully opened. + workbook.ActiveSheetPos = 1; + // Shared strings: + using (MemoryStream sharedStringsFile = workbook.WorkbookArchive.ExtractFileToStream("xl/sharedStrings.xml")) + { + if (sharedStringsFile != null) + { + workbook.SharedStringsDoc = new SaMsXmlDocument(); + workbook.SharedStringsDoc.LoadXml(sharedStringsFile); + } + } + // Styles: + using (MemoryStream stylesFile = workbook.WorkbookArchive.ExtractFileToStream("xl/styles.xml")) + { + if (stylesFile != null) + { + workbook.StylesDoc = new SaMsXmlDocument(); + workbook.StylesDoc.LoadXml(stylesFile); + } + } + // Set worksheet count and open first worksheet. + PopulateWorksheetCount(); + OpenWorksheet(1); + } + else return SetErrorState("Failed to read workbook data"); + } + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + return !HasErrorState(); + } + public override bool SaveDocument (String filePath, int fileFormat, bool bAutomaticallyOverwrite) + { + ClearErrorState(); + if (fileFormat == 0) + fileFormat = (int)XlFileFormat.xlOpenXMLWorkbook; + if (fileFormat != (int)XlFileFormat.xlOpenXMLWorkbook) + SetErrorState("Unsupported file format: " + ((XlFileFormat)fileFormat).ToString()); + if (!HasErrorState() && !workbook.IsValid()) + SetErrorState("Workbook is not open"); + SetErrorState("Saving workbook not supported"); + return !HasErrorState(); + } + public override bool CloseWorkbook () + { + ClearErrorState(); + CloseWorksheet(); + + // Clear workbook. + if (workbook != null) + { + try + { + if (workbook.StylesDoc != null) workbook.StylesDoc.Dispose(); workbook.StylesDoc = null; + if (workbook.SharedStringsDoc != null) workbook.SharedStringsDoc.Dispose(); workbook.SharedStringsDoc = null; + if (workbook.WorkbookDoc != null) workbook.WorkbookDoc.Dispose(); workbook.WorkbookDoc = null; + if (workbook.WorkbookArchive != null) workbook.WorkbookArchive.Dispose(); workbook.WorkbookArchive = null; + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + workbook = null; + } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // W o r k s h e e t + //------------------------------------------------------------------- + public override bool IsWorksheetValid () + { + return (worksheet != null && worksheet.WorksheetDoc != null); + } + public override uint WorksheetCount { get { return workbook.WorksheetCount; } } + private void PopulateWorksheetCount () + { + if (!IsWorkbookValid()) return; + try + { + // Count worksheets in workbook. + SaMsXmlElement nodeWorkbook = workbook.WorkbookDoc.GetRootElement(); + SaMsXmlElement nodeSheets = nodeWorkbook.GetFirstChildElement("sheets"); + workbook.WorksheetCount = (uint)nodeSheets.GetChildElements("sheet").Count; + } + catch (Exception exc) { HandleException("GetWorksheetCount", exc); } + } + public override bool SetWorksheetCount (int worksheetCount) + { + ClearErrorState(); + return SetErrorState("Modifying workbook not supported"); + } + public override bool AddWorksheet(String name) + { + return SetErrorState("Modifying workbook not supported"); + } + public override bool RemoveWorksheet(uint worksheetPos) + { + return SetErrorState("Modifying workbook not supported"); + } + public override bool OpenWorksheet (uint worksheetPos) + { + ClearErrorState(); + if (!workbook.IsValid()) return SetErrorState("Workbook is not open"); + if (worksheetPos > WorksheetCount) return SetErrorState("Invalid sheet specified"); + if (worksheetPos <= 0) worksheetPos = Math.Max(1, workbook.ActiveSheetPos); + CloseWorksheet(); + try + { + worksheet = new Worksheet(); + // Locate worksheet in workbook by 0-index. + SaMsXmlElement workbookElement = workbook.WorkbookDoc.GetRootElement(); + SaMsXmlElement sheetsElement = workbookElement.GetFirstChildElement("sheets"); + long sheetCount = 0; + foreach (SaMsXmlElement sheetElement in sheetsElement.GetChildElements("sheet")) + { + sheetCount++; + if (sheetCount == worksheetPos) + { + // Extract the worksheet data. + uint sheetId = (uint)StringUtil.ToInt(sheetElement.GetAttributeValue("sheetId")); + String worksheetArchivePath = "xl/worksheets/sheet" + worksheetPos.ToString() + ".xml"; + using (MemoryStream worksheetFile = workbook.WorkbookArchive.ExtractFileToStream(worksheetArchivePath)) + { + if (worksheetFile == null) return SetErrorState("Failed to load worksheet data"); + worksheet.WorksheetDoc = new SaMsXmlDocument(); + if (worksheet.WorksheetDoc.LoadXml(worksheetFile)) + { + workbook.ActiveSheetPos = worksheetPos; + worksheet.WorksheetPos = worksheetPos; + worksheet.WorksheetId = sheetId; + worksheet.WorksheetArchivePath = worksheetArchivePath; + worksheet.WorksheetName = sheetElement.GetAttributeValue("name"); + worksheet.ActiveColPos = 1; + worksheet.ActiveRowPos = 1; + SaMsXmlElement nodeWorksheet = worksheet.WorksheetDoc.GetRootElement(); + worksheet.Nodes.Cols = nodeWorksheet.GetFirstChildElement("cols"); + worksheet.Nodes.ActiveCol = worksheet.Nodes.Cols.GetFirstChildElement("col"); + worksheet.Nodes.Rows = nodeWorksheet.GetFirstChildElement("sheetData"); + worksheet.Nodes.ActiveRow = worksheet.Nodes.Rows.GetFirstChildElement("row"); + workbook.ActiveSheetPos = worksheetPos; + } + else return SetErrorState("Failed to read data for worksheet " + worksheetPos.ToString()); + } + break; + } + } + if (worksheet.WorksheetDoc == null) return SetErrorState("Unable to load worksheet " + worksheetPos.ToString()); + } + catch (Exception exc) { HandleException("OpenWorksheet", exc); } + return !HasErrorState(); + } + public override uint WorksheetPos { get { return workbook.ActiveSheetPos; } } + public override String WorksheetName + { + get { return ""; } + set { } + } + public override bool SetWorksheetAttr (SaMsExcelItemAttr attr) + { + return SetErrorState("Not supported"); + } + public override bool CloseWorksheet () + { + ClearErrorState(); + + if (worksheet != null) + { + try + { + if (worksheet.WorksheetDoc != null) worksheet.WorksheetDoc.Dispose(); worksheet.WorksheetDoc = null; + if (worksheet.Nodes.Cols != null) worksheet.Nodes.Cols.Dispose(); worksheet.Nodes.Cols = null; + if (worksheet.Nodes.ActiveCol != null) worksheet.Nodes.ActiveCol.Dispose(); worksheet.Nodes.ActiveCol = null; + if (worksheet.Nodes.Rows != null) worksheet.Nodes.Rows.Dispose(); worksheet.Nodes.Rows = null; + if (worksheet.Nodes.ActiveRow != null) worksheet.Nodes.ActiveRow.Dispose(); worksheet.Nodes.ActiveRow = null; + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + worksheet = null; + } + + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // Worksheet Page Setup. + public override bool SetPageSetup (SaMsExcelPageSetup_Config pageSetupConfig) + { + return SetErrorState("Not supported"); + } + public override bool SetPageBreak (uint col, uint row) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + // C o l u m n s + //------------------------------------------------------------------- + public override uint GetActiveColPos () + { + return worksheet.ActiveColPos; + } + private SaMsXmlElement GetColElement (uint colPos) + { + ClearErrorState(); + try + { + if (worksheet.ActiveColPos == colPos) return worksheet.Nodes.ActiveCol; + int colCount = 0; + foreach (SaMsXmlElement colElement in worksheet.Nodes.Cols.GetChildElements("Col")) + { + if (++colCount == colPos) + { + if (worksheet.Nodes.ActiveCol != null) worksheet.Nodes.ActiveCol.Dispose(); + worksheet.ActiveColPos = colPos; + worksheet.Nodes.ActiveCol = colElement; + return colElement; + } + } + } + catch (Exception exc) { HandleException("GetColElement", exc); } + return new SaMsXmlElement(null); + } + public override double GetColWidth (uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) + { + ClearErrorState(); + try + { + // Retrieve width (in points) from column. + SaMsXmlNode nodeCol = GetColElement(colPos); + double width = nodeCol.GetAttributeValue("width").ToDouble(); + // Adjust for units. + if (unit == SaExcelLogicalUnit.Pixel) return PointsToPixels(width, false); + if (unit == SaExcelLogicalUnit.Cm) return PointsToCms(width); + if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(width); + return width; + } + catch (Exception exc) { HandleException("GetColWidth", exc); } + return 0.0; + } + public override bool SetColWidth (uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + // R o w s + //------------------------------------------------------------------- + public override uint GetActiveRowPos () + { + return worksheet.ActiveRowPos; + } + SaMsXmlElement GetRowElement (uint rowPos) + { + ClearErrorState(); + try + { + if (worksheet.ActiveRowPos == rowPos) return worksheet.Nodes.ActiveRow; + foreach (SaMsXmlElement rowElement in worksheet.Nodes.Rows.GetChildElements("row")) + { + if (rowElement.GetAttributeValue("r").ToLong() == rowPos) + { + if (worksheet.Nodes.ActiveRow != null) worksheet.Nodes.ActiveRow.Dispose(); + worksheet.ActiveRowPos = rowPos; + worksheet.Nodes.ActiveRow = rowElement; + return rowElement; + } + } + } + catch (Exception exc) { HandleException("GetRowElement", exc); } + return new SaMsXmlElement(null); + } + public override double GetRowHeight (uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) + { + ClearErrorState(); + try + { + // Retrieve height (in points) from row. + SaMsXmlElement rowElement = GetRowElement(rowPos); + double height = rowElement.GetAttributeValue("ht").ToDouble(); + // Adjust for units. + if (unit == SaExcelLogicalUnit.Pixel) return PointsToPixels(height, true); + if (unit == SaExcelLogicalUnit.Cm) return PointsToCms(height); + if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(height); + return height; + } + catch (Exception exc) { HandleException("GetRowHeight", exc); } + return 0.0; + } + public override bool SetRowHeight (uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + // R o w s + //------------------------------------------------------------------- + public override List GetRowDataValues (uint rowPos, int maxColumns = 0) + { + ClearErrorState(); + List values = new List(); + try + { + SaMsXmlElement rowElement = GetRowElement(rowPos); + foreach (SaMsXmlElement cellElement in rowElement.GetChildElements("c")) + { + // CellId may be needed in case cells are skipped in the data. + // Doesn't appear to be the case, even when previous cell is merged with next. + String cellId = cellElement.GetAttributeValue("r"); + values.Add(GetCellDataValue(cellElement)); + if (maxColumns > 0 && values.Count >= maxColumns) break; + } + } + catch (Exception exc) { HandleException("GetRowDataValues", exc); } + return values; + } + + //------------------------------------------------------------------- + // C e l l s + //------------------------------------------------------------------- + SaMsXmlElement GetCellElement (uint colPos, uint rowPos) + { + ClearErrorState(); + String cellId = GetCellId(colPos,rowPos); + try + { + SaMsXmlElement rowElement = GetRowElement(rowPos); + foreach (SaMsXmlElement cellElement in rowElement.GetChildElements("c")) + { + if (cellElement.GetAttributeValue("r").EqualsCI(cellId)) + return cellElement; + } + } + catch (Exception exc) { HandleException("GetCellElement", exc); } + return new SaMsXmlElement(null); + } + public override void SetActiveCell (uint colPos, uint rowPos) + { + // ToDo SetActiveCell. + SetErrorState("Not supported"); + } + //------------------------------------------------------------------- + private bool IsCellFormula (uint colPos, uint rowPos) + { + ClearErrorState(); + bool bIsFormula = false; + try + { + SaMsXmlElement cellElement = GetCellElement(colPos,rowPos); + bIsFormula = !cellElement.GetAttributeValue("f").IsEmpty(); + } + catch (Exception exc) { HandleException("IsCellFormula", exc); } + return bIsFormula; + } + private bool IsCellNumeric (uint colPos, uint rowPos) + { + ClearErrorState(); + try + { + SaMsXmlElement cellElement = GetCellElement(colPos,rowPos); + SaMsExcelStyle cellStyle = GetCellStyle(cellElement); + return IsCellNumeric(cellElement, cellStyle); + } + catch (Exception exc) { HandleException("IsCellNumeric", exc); } + return false; + } + private bool IsCellNumeric (SaMsXmlElement cellElement) + { + ClearErrorState(); + SaMsExcelStyle cellStyle = GetCellStyle(cellElement); + return IsCellNumeric(cellElement, cellStyle); + } + private bool IsCellNumeric (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle) + { + ClearErrorState(); + return (cellElement.GetAttributeValue("t").IsEmpty() && !IsDateTimeStyle(cellStyle.NumFmtCode)); + } + private bool IsCellDate (uint colPos, uint rowPos) + { + ClearErrorState(); + bool bIsDate = false; + try + { + SaMsXmlElement cellElement = GetCellElement(colPos,rowPos); + SaMsExcelStyle cellStyle = GetCellStyle(cellElement); + return IsCellDate(cellElement, cellStyle); + } + catch (Exception exc) { HandleException("IsCellDate", exc); } + return bIsDate; + } + private bool IsCellDate (SaMsXmlElement cellElement) + { + return IsCellDate(cellElement, GetCellStyle(cellElement)); + } + private bool IsCellDate (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle) + { + ClearErrorState(); + return IsDateTimeStyle(cellStyle.NumFmtCode); + } + //------------------------------------------------------------------- + public override String GetCellFormula (uint colPos, uint rowPos) + { + ClearErrorState(); + try + { + SaMsXmlElement cellElement = GetCellElement(colPos,rowPos); + String formula = cellElement.GetAttributeValue("f"); + if (formula.IsEmpty()) + formula = GetCellText(cellElement, true); + return formula; + } + catch (Exception exc) { HandleException("GetCellFormula", exc); } + return ""; + } + private String GetCellText (SaMsXmlElement cellElement, bool trimValue = true) + { + ClearErrorState(); + String value = ""; + try + { + if (cellElement.GetAttributeValue("t").EqualsCI("s")) + value = GetSharedString(cellElement); + else + value = cellElement.GetChildText("v"); + if (trimValue) value.TrimAll(); + } + catch (Exception exc) { HandleException("GetCellText", exc); } + return value; + } + public override DataValue GetCellDataValue (uint colPos, uint rowPos) + { + return GetCellDataValue(GetCellElement(colPos, rowPos), false); + } + private DataValue GetCellDataValue (SaMsXmlElement cellElement, bool trimTextValue = true) + { + ClearErrorState(); + try + { + SaMsExcelStyle cellStyle = GetCellStyle(cellElement); + if (cellElement.GetAttributeValue("t").EqualsCI("s")) + { + String value = GetSharedString(cellElement); + if (trimTextValue) value = value.TrimAll(); + return new DataValue(value); + } + else + { + String value = cellElement.GetChildText("v"); + if (IsDateTimeStyle(cellStyle.NumFmtCode)) + return new DataValue(DateTime.FromOADate(value.ToDouble())); + if (IsCellNumeric(cellElement, cellStyle)) + { + if (value.IsNumeric()) + return new DataValue(value.ToLong()); + if (value.IsDecimal()) + { +#if DEBUG + //if (StringUtil.ToInt(value) > 600) Debugger.Break(); +#endif + return new DataValue(value.ToDecimal()); + } + } + if (trimTextValue) value = value.TrimAll(); + return new DataValue(value); + } + } + catch (Exception exc) { HandleException("GetCellDataValue", exc); } + return new DataValue(); + } + //------------------------------------------------------------------- + // Shared string for cell. + private String GetSharedString (SaMsXmlElement nodeElement) + { + ClearErrorState(); + try + { + SaMsXmlElement sharedStringElement = GetSharedStringElement(nodeElement); + return sharedStringElement.GetChildText("t"); + } + catch (Exception exc) { HandleException("GetSharedString", exc); } + return ""; + } + private SaMsXmlElement GetSharedStringElement (SaMsXmlElement cellElement) + { + ClearErrorState(); + if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid) return null; + if (!cellElement.GetAttributeValue("t").EqualsCI("s") || !cellElement.GetChildText("v").IsNumeric()) return null; + // Shared strings are indexed from 0. + long sharedStringIdx = -1; + try + { + long iIdx = cellElement.GetChildText("v").ToLong(); + SaMsXmlElement sstElement = workbook.SharedStringsDoc.GetRootElement(); + foreach (SaMsXmlElement siElement in sstElement.GetChildElements("si")) + { + if (++sharedStringIdx == iIdx) + return siElement; + } + } + catch (Exception exc) { HandleException("GetSharedStringNode", exc); } + return new SaMsXmlElement(null); + } + //------------------------------------------------------------------- + public override bool SetCellFormula (uint colPos, uint rowPos, String value) + { + return SetErrorState("Not supported"); + } + public override bool SetCellFormula (uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr) + { + return SetErrorState("Not supported"); + } + public override bool SetRowFormulas (uint colPosStart, uint rowPos, List values) + { + return SetErrorState("Not supported"); + } + public override bool SetRangeFormulas (SaMsExcelRange range, List values) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + // C e l l S t y l e + //------------------------------------------------------------------- + private String GetBuiltInStyleFormat (int numFmtId) + { + // Ref. http://stackoverflow.com/questions/4730152/what-indicates-an-office-open-xml-cell-contains-a-date-time-value + switch (numFmtId) + { + // + case 0: return "General"; + case 1: return "0"; + case 2: return "0.00"; + case 3: return "#,##0"; + case 4: return "#,##0.00"; + // + case 9: return "0%"; + case 10: return "0.00%"; + case 11: return "0.00E+00"; + case 12: return "# ?/?"; + case 13: return "# ??/??"; + case 14: return "mm-dd-yy"; + case 15: return "d-mmm-yy"; + case 16: return "d-mmm"; + case 17: return "mmm-yy"; + case 18: return "h:mm AM/PM"; + case 19: return "h:mm:ss AM/PM"; + case 20: return "h:mm"; + case 21: return "h:mm:ss"; + case 22: return "m/d/yy h:mm"; + // + case 37: return "#,##0 ;(#,##0)"; + case 38: return "#,##0 ;[Red](#,##0)"; + case 39: return "#,##0.00;(#,##0.00)"; + case 40: return "#,##0.00;[Red](#,##0.00)"; + // + case 44: return "_(\"$\"* #,##0.00_);_(\"$\"* \\(#,##0.00\\);_(\"$\"* \"-\"??_);_(@_)"; + case 45: return "mm:ss"; + case 46: return "[h]:mm:ss"; + case 47: return "mmss.0"; + case 48: return "##0.0E+0"; + case 49: return "@"; + // + case 27: return "[$-404]e/m/d"; + case 30: return "m/d/yy"; + case 36: return "[$-404]e/m/d"; + case 50: return "[$-404]e/m/d"; + case 57: return "[$-404]e/m/d"; + // + case 59: return "t0"; + case 60: return "t0.00"; + case 61: return "t#,##0"; + case 62: return "t#,##0.00"; + case 67: return "t0%"; + case 68: return "t0.00%"; + case 69: return "t# ?/?"; + case 70: return "t# ??/??"; + } + return ""; + } + private SaMsExcelStyle GetCellStyle (SaMsXmlElement cellElement) + { + ClearErrorState(); + SaMsExcelStyle style = new SaMsExcelStyle(); + if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid || !cellElement.GetAttributeValue("s").IsNumeric()) return style; + // Styles are indexed from 0. + long styleIdx = -1; + try + { + long cellStyleIdx = cellElement.GetAttributeValue("s").ToLong(); + SaMsXmlElement styleSheetElement = workbook.SharedStringsDoc.GetRootElement(); + SaMsXmlElement cellXfsElement = styleSheetElement.GetFirstChildElement("cellXfs"); + foreach (SaMsXmlElement xfElement in styleSheetElement.GetChildElements("xf")) + { + if (++styleIdx == cellStyleIdx) + { + // Construct style. + style.NumFmtId = (int)xfElement.GetAttributeValue("numFmtId").ToLong(); + style.FontId = (int)xfElement.GetAttributeValue("fontId").ToLong(); + style.FillId = (int)xfElement.GetAttributeValue("fillId").ToLong(); + style.BorderId = (int)xfElement.GetAttributeValue("borderId").ToLong(); + style.XfId = (int)xfElement.GetAttributeValue("xfId").ToLong(); + style.QuotePrefix = xfElement.GetAttributeValue("quotePrefix").ToBool(); + style.PivotButton = xfElement.GetAttributeValue("pivotButton").ToBool(); + style.ApplyNumberFormat = xfElement.GetAttributeValue("applyNumberFormat").ToBool(); + style.ApplyFont = xfElement.GetAttributeValue("applyFont").ToBool(); + style.ApplyFill = xfElement.GetAttributeValue("applyFill").ToBool(); + style.ApplyBorder = xfElement.GetAttributeValue("applyBorder").ToBool(); + style.ApplyAlignment = xfElement.GetAttributeValue("applyAlignment").ToBool(); + style.ApplyProtection = xfElement.GetAttributeValue("applyProtection").ToBool(); + // Alignment. + SaMsXmlNode nodeAlignment = xfElement.GetFirstChildElement("alignment"); + String sAlignHorizontal = nodeAlignment.GetAttributeValue("horizontal"); + if (sAlignHorizontal.EqualsCI("center")) style.AlignHorizontal = XlHAlign.xlHAlignCenter; + else if (sAlignHorizontal.EqualsCI("centerContinuous")) style.AlignHorizontal = XlHAlign.xlHAlignCenterAcrossSelection; + else if (sAlignHorizontal.EqualsCI("distributed")) style.AlignHorizontal = XlHAlign.xlHAlignDistributed; + else if (sAlignHorizontal.EqualsCI("fill")) style.AlignHorizontal = XlHAlign.xlHAlignFill; + else if (sAlignHorizontal.EqualsCI("justify")) style.AlignHorizontal = XlHAlign.xlHAlignJustify; + else if (sAlignHorizontal.EqualsCI("left")) style.AlignHorizontal = XlHAlign.xlHAlignLeft; + else if (sAlignHorizontal.EqualsCI("right")) style.AlignHorizontal = XlHAlign.xlHAlignRight; + String sAlignVertical = nodeAlignment.GetAttributeValue("vertical"); + if (sAlignVertical.EqualsCI("center")) style.AlignVertical = XlVAlign.xlVAlignCenter; + else if (sAlignVertical.EqualsCI("top")) style.AlignVertical = XlVAlign.xlVAlignTop; + else if (sAlignVertical.EqualsCI("bottom")) style.AlignVertical = XlVAlign.xlVAlignBottom; + else if (sAlignVertical.EqualsCI("distributed")) style.AlignVertical = XlVAlign.xlVAlignDistributed; + else if (sAlignVertical.EqualsCI("justify")) style.AlignVertical = XlVAlign.xlVAlignJustify; + // Number format. + if (style.ApplyNumberFormat) + { + if (style.NumFmtId >= 164) + { + SaMsXmlElement numFmtsElement = styleSheetElement.GetFirstChildElement("NumFmts"); + foreach (SaMsXmlElement numFmtElement in numFmtsElement.GetChildElements("numFmt")) + { + if (numFmtElement.GetAttributeValue("numFmtId").ToLong() == style.NumFmtId) + { + style.NumFmtCode = numFmtElement.GetAttributeValue("formatCode"); + break; + } + } + } + else style.NumFmtCode = GetBuiltInStyleFormat(style.NumFmtId); + } + // Font. + if (style.ApplyFont) + { + } + // Fill. + if (style.ApplyFill) + { + } + // Borders. + if (style.ApplyBorder) + { + } + // Alignment. + if (style.ApplyAlignment) + { + } + // Protection. + if (style.ApplyProtection) + { + } + break; + } + } + } + catch (Exception exc) { HandleException("GetStyleNode", exc); } + return style; + } + private bool IsDateStyle (String numFormat) + { + // Ref. http://stackoverflow.com/questions/19034805/how-to-distinguish-inline-numbers-from-ole-automation-date-numbers-in-openxml-sp/19582685#19582685 + if (IsTimeStyle(numFormat)) return false; + if (numFormat.Contains("d")) return true; + if (numFormat.Contains("m")) return true; + if (numFormat.Contains("y")) return true; + return false; + } + private bool IsTimeStyle (String numFormat) + { + if (numFormat.Contains("h")) return true; + if (numFormat.Contains(":mm")) return true; + if (numFormat.Contains("mm:")) return true; + if (numFormat.Contains(":ss")) return true; + return false; + } + private bool IsDateTimeStyle (String numFormat) + { + return (IsDateStyle(numFormat) || IsTimeStyle(numFormat)); + } + + //------------------------------------------------------------------- + // Cell attributes. + public override bool SetRangeAttr (SaMsExcelRange range, SaMsExcelItemAttr attr) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + // Add image to sheet. + public override bool InsertImage (SaMsExcelImage_Config imageConfig) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + public override bool FreezePanes (uint colPos, uint rowPos) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + public override bool AutoFit (SaMsExcelRange range) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + public override bool SelectRange (SaMsExcelRange range) + { + return SetErrorState("Not supported"); + } + + //------------------------------------------------------------------- + } + + //======================================================================= +} diff --git a/SacsStandardData/Data/Excel/SaMsSpreadsheet_OpenXml.cs b/SacsStandardData/Data/Excel/SaMsSpreadsheet_OpenXml.cs new file mode 100644 index 0000000..7a2d11a --- /dev/null +++ b/SacsStandardData/Data/Excel/SaMsSpreadsheet_OpenXml.cs @@ -0,0 +1,656 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +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; + +namespace Sarand.Net.Standard.Data.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(exc.GetType().Name + ".CreateWorkbook " + 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(exc.GetType().Name + ".OpenWorkbook " + ExceptionUtil.GetErrorStateMessage(exc)); } + return (workbook != null); + } + 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 !HasErrorState(); + } + 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(exc.GetType().Name + ".CloseWorkbook " + ExceptionUtil.GetErrorStateMessage(exc)); } + workbook = null; + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // W o r k s h e e t + //------------------------------------------------------------------- + public override bool IsWorksheetValid() + { + return (worksheet != null); + } + 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 !HasErrorState(); + } + 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; + } + public override bool OpenWorksheet(uint worksheetPos) + { + String fn = GetType().Name + ".OpenWorksheet"; + 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(fn + " Failed to open worksheet " + worksheetPos); + SetErrorState("Failed to open worksheet " + worksheetPos); + } + + 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(SaMsExcelItemAttr attr) + { + ClearErrorState(); + try + { + // ToDo OpenXml SetWorksheetAttr + } + catch (Exception exc) { HandleException("SetWorksheetAttr", exc); } + return !HasErrorState(); + } + 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("CloseWorksheet", exc); } + worksheet = null; + activeWorksheetPos = 0; + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // 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("SetPageSetup", exc); } + return !HasErrorState(); + } + 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("SetPageSetup", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + 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 GetActiveColPos() + { + if (worksheet == null) return 0; + try + { + return worksheet.ActiveColumnPos; + } + catch (Exception exc) { HandleException("GetActiveCol", 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("GetColWidth", exc); } + return columnWidth; + } + public override bool SetColWidth(uint colPos, double columnWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) + { + ClearErrorState(); + try + { + // ToDo OpenXML SetColWidth. + } + catch (Exception exc) { HandleException("SetColWidth", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // R o w s + //------------------------------------------------------------------- + public override uint GetActiveRowPos() + { + try + { + // ToDo OpenXML GetActiveRowPos. + } + catch (Exception exc) { HandleException("GetActiveRowPos", exc); } + return 0; + } + public override List GetRowDataValues(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("GetRowHeight", exc); } + return rowHeight; + } + public override bool SetRowHeight(uint rowPos, double rowHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point) + { + ClearErrorState(); + try + { + // ToDo OpenXML SetRowHeight. + } + catch (Exception exc) { HandleException("SetRowHeight", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // 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 DataValue GetCellDataValue(uint colPos, uint rowPos) + { + // ToDo OpenXML GetCellDataValue. + return new DataValue(); + } + public override bool SetCellFormula(uint colPos, uint rowPos, String value) + { + // ToDo OpenXML SetCellFormula. + return true; + } + public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr) + { + // ToDo OpenXML SetCellFormula. + return true; + } + public override bool SetRowFormulas(uint colPosStart, uint rowPos, List values) + { + // ToDo OpenXML SetRowFormulas. + return true; + } + public override bool SetRangeFormulas(SaMsExcelRange range, List values) + { + // ToDo OpenXML SetRangeFormulas. + return true; + } + + //------------------------------------------------------------------- + // Cell attributes. + public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelItemAttr attr) + { + ClearErrorState(); + try + { + // ToDo OpenXML SetRangeAttr. + } + catch (Exception exc) { HandleException("SetRangeAttr", exc); } + return !HasErrorState(); + } + private bool SetRangeAttr(Range oRange, SaMsExcelItemAttr attr) + { + ClearErrorState(); + try + { + // ToDo OpenXML SetRangeAttr. + } + catch (Exception exc) { HandleException("SetRangeAttr", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // 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("InsertImage", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + public override bool FreezePanes(uint colPos, uint rowPos) + { + ClearErrorState(); + try + { + // ToDo OpenXML FreezePanes. + } + catch (Exception exc) { HandleException("FreezePanes", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + public override bool AutoFit(SaMsExcelRange range) + { + ClearErrorState(); + try + { + // ToDo OpenXML AutoFit. + } + catch (Exception exc) { HandleException("AutoFit", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + public override bool SelectRange(SaMsExcelRange range) + { + ClearErrorState(); + try + { + // ToDo OpenXML SelectRange. + } + catch (Exception exc) { HandleException("SelectRange", exc); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardData/Data/Xml/SaMsXmlDocument.cs b/SacsStandardData/Data/Xml/SaMsXmlDocument.cs new file mode 100644 index 0000000..edd6e69 --- /dev/null +++ b/SacsStandardData/Data/Xml/SaMsXmlDocument.cs @@ -0,0 +1,121 @@ +using System; +using System.IO; +using System.Text; +using System.Xml; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Utils; + +namespace Sarand.Net.Standard.Data.Xml +{ + //======================================================================= + public class SaMsXmlDocument : SaErrorStateItem + { + //------------------------------------------------------------------- + // Data members. + private XmlDocument document = new XmlDocument(); + + //------------------------------------------------------------------- + // Construction. + public SaMsXmlDocument () + { + } + protected override void Dispose (bool disposing) + { + if (disposing) + { + document = null; + } + } + + //------------------------------------------------------------------- + // Properties. + public bool Valid { get { return (document != null); } } + + //------------------------------------------------------------------- + // O p e n + //------------------------------------------------------------------- + public bool CreateNew (String rootElementName = "") + { + ClearErrorState(); + document = new XmlDocument(); + if (!StringUtil.IsEmpty(rootElementName)) + document.AppendElement(rootElementName); + return !HasErrorState(); + } + public bool LoadXml (String xml) + { + ClearErrorState(); + document = new XmlDocument(); + try + { + document.LoadXml(xml); + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + return !HasErrorState(); + } + public bool LoadXml (Stream xml) + { + ClearErrorState(); + document = new XmlDocument(); + try + { + xml.Seek(0, SeekOrigin.Begin); + document.Load(xml); + } + catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); } + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // C o n v e r s i o n + //------------------------------------------------------------------- + public static Encoding DefaultEncoding { get; } = Encoding.UTF8; + public String GetXml (Encoding encoding = null) + { + return document.GetXml(encoding != null ? encoding : DefaultEncoding); + } + public String FormatXml (Encoding encoding = null) + { + return document.FormatXml(encoding != null ? encoding : DefaultEncoding); + } + + //------------------------------------------------------------------- + // E l e m e n t s + //------------------------------------------------------------------- + public SaMsXmlElement GetRootElement () + { + if (document != null) return new SaMsXmlElement(document.DocumentElement); + return null; + } + public SaMsXmlElement SetRootElement (String name) + { + // Clear existing root element. + if (document.DocumentElement != null) + document.DocumentElement.ParentNode.RemoveAll(); + // Add the new root element. + return new SaMsXmlElement(document.AppendElement(name)); + } + public SaMsXmlElement SetRootElement (SaXmlNamespace xmlNamespace, String name) + { + // Clear existing root element. + if (document.DocumentElement != null) + document.DocumentElement.ParentNode.RemoveAll(); + // Add the new root element. + return new SaMsXmlElement(document.AppendElement(xmlNamespace, name)); + } + public SaMsXmlElement SetRootElement (SaMsXmlElement rootNode) + { + // Clear existing root element. + if (document.DocumentElement != null) + document.DocumentElement.ParentNode.RemoveAll(); + // Import the node into the document before appending. + XmlNode importNode = document.ImportNode(rootNode.Element, true); + document.AppendChild(importNode); + return rootNode; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardData/Data/Xml/SaMsXmlElement.cs b/SacsStandardData/Data/Xml/SaMsXmlElement.cs new file mode 100644 index 0000000..025eda9 --- /dev/null +++ b/SacsStandardData/Data/Xml/SaMsXmlElement.cs @@ -0,0 +1,178 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Utils; + +namespace Sarand.Net.Standard.Data.Xml +{ + //======================================================================= + public class SaMsXmlElement : SaMsXmlNode + { + //------------------------------------------------------------------- + // Data members. + + //------------------------------------------------------------------- + // Construction. + internal SaMsXmlElement (XmlElement element) : + base(element) + { + } + protected override void Dispose (bool disposing) + { + if (disposing) + { + } + base.Dispose(disposing); + } + + //------------------------------------------------------------------- + // Properties. + internal XmlElement Element { get { return (node as XmlElement); } } + public override bool Valid { get { return (Element != null); } } + + //------------------------------------------------------------------- + // A t t r i b u t e s + //------------------------------------------------------------------- + public Dictionary GetAttributes () + { + Dictionary attributes = new Dictionary(); + foreach (XmlAttribute attribute in Element.Attributes) + attributes[attribute.Name] = attribute.Value; + return attributes; + } + public bool HasAttribute (String name, bool caseInsensitive = false) + { + foreach (XmlAttribute attribute in Element.Attributes) + { + if ((!caseInsensitive && attribute.Name.Equals(name)) || (caseInsensitive && attribute.Name.EqualsCI(name))) + return true; + } + return false; + } + public String GetAttribute (String name, bool caseInsensitive = false) + { + foreach (XmlAttribute attribute in Element.Attributes) + { + if ((!caseInsensitive && attribute.Name.Equals(name)) || (caseInsensitive && attribute.Name.EqualsCI(name))) + return attribute.Value; + } + return ""; + } + public void SetAttribute (String name, String value) + { + Element.SetAttribute(name, value); + } + public bool RemoveAttribute (String name, bool caseInsensitive = false) + { + if (!HasAttribute(name, caseInsensitive)) return false; + for (int attributeIdx =0; attributeIdx < Element.Attributes.Count; attributeIdx++) + { + XmlAttribute attribute = Element.Attributes[attributeIdx]; + if ((!caseInsensitive && attribute.Name.Equals(name)) || (caseInsensitive && attribute.Name.EqualsCI(name))) + { + Element.Attributes.RemoveAt(attributeIdx); + attributeIdx--; + } + } + return true; + } + + //------------------------------------------------------------------- + // C h i l d E l e m e n t s + //------------------------------------------------------------------- + public List GetChildElements (String name = "") + { + List childElements = new List(); + XmlElement element = Element; + if (element == null) return childElements; + foreach (XmlNode childNode in element.ChildNodes) + { + if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name)) + childElements.Add(new SaMsXmlElement(childNode as XmlElement)); + } + return childElements; + } + public bool HasChildElement (String name) + { + XmlElement element = Element; + if (element == null) return false; + foreach (XmlNode childNode in element.ChildNodes) + { + if (childNode.NodeType == XmlNodeType.Element && StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name)) + return true; + } + return false; + } + public SaMsXmlElement GetFirstChildElement (String name = "") + { + XmlElement element = Element; + if (element == null) return null; + foreach (XmlNode childNode in element.ChildNodes) + { + if (childNode.NodeType == XmlNodeType.Element && StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name)) + return new SaMsXmlElement(childNode as XmlElement); + } + return new SaMsXmlElement(null); + } + + //------------------------------------------------------------------- + // A p p e n d E l e m e n t s + //------------------------------------------------------------------- + /// Append element to node by name. + public SaMsXmlElement AppendElement (String name, String text = "") + { + XmlDocument doc = Element.OwnerDocument; + XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(name)); + if (!StringUtil.IsEmpty(text)) + child.AppendChild(doc.CreateTextNode(text)); + return new SaMsXmlElement(child); + } + public SaMsXmlElement AppendElement (SaXmlNamespace xmlNamespace, String name, String text = "") + { + XmlDocument doc = Element.OwnerDocument; + XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(xmlNamespace.Prefix, name, xmlNamespace.Uri)); + if (!StringUtil.IsEmpty(text)) + child.AppendChild(doc.CreateTextNode(text)); + return new SaMsXmlElement(child); + } + //------------------------------------------------------------------- + /// Append element to node by name if value supplied. + public SaMsXmlElement AppendNonBlankElement (String name, String text) + { + if (StringUtil.IsEmpty(text)) return null; + XmlDocument doc = Element.OwnerDocument; + XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(name)); + if (!StringUtil.IsEmpty(text)) + child.AppendChild(doc.CreateTextNode(text)); + return new SaMsXmlElement(child); + } + public SaMsXmlElement AppendNonBlankElement (SaXmlNamespace xmlNamespace, String name, String text) + { + if (StringUtil.IsEmpty(text)) return null; + XmlDocument doc = Element.OwnerDocument; + XmlElement child = (XmlElement)Element.AppendChild(doc.CreateElement(xmlNamespace.Prefix, name, xmlNamespace.Uri)); + if (!StringUtil.IsEmpty(text)) + child.AppendChild(doc.CreateTextNode(text)); + return new SaMsXmlElement(child); + } + + //------------------------------------------------------------------- + /// Append element to node. + public SaMsXmlElement AppendElement (SaMsXmlElement element) + { + // Import the node into the document before appending. + XmlDocument doc = Element.OwnerDocument; + XmlNode appendNode = doc.ImportNode(element.Element, true); + XmlElement child = (XmlElement)Element.AppendChild(appendNode); + return new SaMsXmlElement(child); + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardData/Data/Xml/SaMsXmlNode.cs b/SacsStandardData/Data/Xml/SaMsXmlNode.cs new file mode 100644 index 0000000..db08440 --- /dev/null +++ b/SacsStandardData/Data/Xml/SaMsXmlNode.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Utils; + +namespace Sarand.Net.Standard.Data.Xml +{ + //======================================================================= + public class SaMsXmlNode : SaErrorStateItem + { + //------------------------------------------------------------------- + // Data members. + internal XmlNode node; + + //------------------------------------------------------------------- + // Construction. + internal SaMsXmlNode (XmlNode node) + { + this.node = node; + } + protected override void Dispose (bool disposing) + { + if (disposing) + { + node = null; + } + base.Dispose(disposing); + } + + //------------------------------------------------------------------- + // Properties. + internal XmlDocument OwnerDocument { get { return node != null ? node.OwnerDocument : null; } } + public String NamespaceURI { get { return node != null ? node.NamespaceURI : ""; } } + public String Prefix { get { return node != null ? node.Prefix : ""; } } + //public String Name { get { return node != null ? node.Name : ""; } } + public String LocalName { get { return node != null ? node.LocalName : ""; } } + public virtual bool Valid { get { return (node != null); } } + + //------------------------------------------------------------------- + // A t t r i b u t e s + //------------------------------------------------------------------- + public String GetAttributeValue (String attributeName) + { + if (StringUtil.IsEmpty(attributeName) || node == null) return ""; + foreach (XmlAttribute attribute in node.Attributes) + { + if (attribute.Name.EqualsCI(attributeName)) + return attribute.Value; + } + return ""; + } + + //------------------------------------------------------------------- + // T e x t + //------------------------------------------------------------------- + public String GetText () + { + if (node == null) return ""; + foreach (XmlNode childNode in node.ChildNodes) + { + if (childNode.NodeType == XmlNodeType.Text || childNode.NodeType == XmlNodeType.CDATA) + return childNode.Value; + } + return ""; + } + + //------------------------------------------------------------------- + // C h i l d N o d e s + //------------------------------------------------------------------- + public List GetChildNodes (String name = "") + { + List childNodes = new List(); + if (node == null) return childNodes; + foreach (XmlNode childNode in node.ChildNodes) + { + if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name)) + childNodes.Add(new SaMsXmlNode(childNode)); + } + return childNodes; + } + public bool HasChildNode (String name) + { + if (node == null) return false; + foreach (XmlNode childNode in node.ChildNodes) + { + if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name)) + return true; + } + return false; + } + public SaMsXmlNode GetFirstChildNode (String name = "") + { + if (node == null) return new SaMsXmlNode(null); + foreach (XmlNode childNode in node.ChildNodes) + { + if (StringUtil.IsEmpty(name) || childNode.Name.EqualsCI(name)) + return new SaMsXmlNode(childNode); + } + return new SaMsXmlNode(null); + } + public String GetChildText (String name, String defaultValue = "") + { + SaMsXmlNode childNode = GetFirstChildNode(name); + if (childNode != null) + return childNode.GetText(); + return defaultValue; + } + + //------------------------------------------------------------------- + } + //======================================================================= + public static class SaMsXmlNodeList + { + } + + //======================================================================= +} diff --git a/SacsStandardData/Data/Xml/SaMsXmlUtil.cs b/SacsStandardData/Data/Xml/SaMsXmlUtil.cs new file mode 100644 index 0000000..11dd008 --- /dev/null +++ b/SacsStandardData/Data/Xml/SaMsXmlUtil.cs @@ -0,0 +1,125 @@ +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Xml; + +namespace Sarand.Net.Standard.Data.Xml +{ + //======================================================================= + public class SaXmlNamespace + { + public SaXmlNamespace (String prefix, String uri) + { + Prefix = prefix; + Uri = uri; + } + public String Prefix { get; } + public String Uri { get; } + } + + //======================================================================= + public static class SaMsXmlUtil + { + //------------------------------------------------------------------- + // Data members. + public static Encoding DefaultEncoding { get; } = Encoding.UTF8; + + //------------------------------------------------------------------- + /// Retrieve the Xml Declaration from the XML document. + public static XmlDeclaration GetXmlDeclaration (this XmlDocument xmlDoc) + { + return xmlDoc.ChildNodes.OfType().FirstOrDefault(); + } + + //------------------------------------------------------------------- + // Convert XML document to string. + public static String GetXml (this XmlDocument xmlDoc, Encoding encoding = null) + { + // Ensure correct encoding for generated XML data. + if (encoding == null) encoding = DefaultEncoding; + XmlWriterSettings settings = new XmlWriterSettings() { Encoding = encoding }; + using (var stringWriter = new StringWriter()) + using (var xmlTextWriter = XmlWriter.Create(stringWriter, settings)) + { + // Ensure that the document has the requested encoding in its XML declaration. + XmlDeclaration xmlDeclaration = xmlDoc.GetXmlDeclaration(); + if (xmlDeclaration == null) + { + xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", encoding.WebName, null); + xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement); + } + else xmlDeclaration.Encoding = encoding.WebName; + // Write the document to String. + xmlDoc.WriteTo(xmlTextWriter); + xmlTextWriter.Flush(); + return stringWriter.GetStringBuilder().ToString(); + } + } + public static String FormatXml (this XmlDocument xmlDoc, Encoding encoding = null) + { + // Ensure correct encoding for generated XML data. + if (encoding == null) encoding = DefaultEncoding; + XmlWriterSettings settings = new XmlWriterSettings() { Encoding = encoding, Indent = true }; + using (MemoryStream memoryStream = new MemoryStream()) + using (var xmlTextWriter = new XmlTextWriter(memoryStream, encoding)) + { + // XML output format. + xmlTextWriter.Formatting = Formatting.Indented; + // Ensure that the document has the requested encoding in its XML declaration. + XmlDeclaration xmlDeclaration = xmlDoc.GetXmlDeclaration(); + if (xmlDeclaration == null) + { + xmlDeclaration = xmlDoc.CreateXmlDeclaration("1.0", encoding.WebName, null); + xmlDoc.InsertBefore(xmlDeclaration, xmlDoc.DocumentElement); + } + else xmlDeclaration.Encoding = encoding.WebName; + // Write the document to String. + xmlDoc.WriteTo(xmlTextWriter); + xmlTextWriter.Flush(); + memoryStream.Flush(); + memoryStream.Position = 0; + using (StreamReader streamReader = new StreamReader(memoryStream)) + { + return streamReader.ReadToEnd(); + } + } + } + + //------------------------------------------------------------------- + // Append element to node. + public static XmlElement AppendElement (this XmlNode node, String name, String text = "") + { + XmlDocument doc = (node is XmlDocument ? node as XmlDocument : node.OwnerDocument); + XmlElement child = (XmlElement)node.AppendChild(doc.CreateElement(name)); + if (!StringUtil.IsEmpty(text)) + child.AppendChild(doc.CreateTextNode(text)); + return child; + } + public static XmlElement AppendElement (this XmlNode node, SaXmlNamespace xmlNamespace, String name, String text = "") + { + XmlDocument doc = (node is XmlDocument ? node as XmlDocument : node.OwnerDocument); + XmlElement child = (XmlElement)node.AppendChild(doc.CreateElement(xmlNamespace.Prefix, name, xmlNamespace.Uri)); + if (!StringUtil.IsEmpty(text)) + child.AppendChild(doc.CreateTextNode(text)); + return child; + } + + //------------------------------------------------------------------- + // Get child text. + public static String GetChildText (this XmlNode node, String name) + { + foreach (XmlNode child in node.ChildNodes) + if (child.Name.EqualsCI(name)) + return child.InnerText; + return String.Empty; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardData/Data/Zip/SaMsZipArchive.cs b/SacsStandardData/Data/Zip/SaMsZipArchive.cs new file mode 100644 index 0000000..97faf88 --- /dev/null +++ b/SacsStandardData/Data/Zip/SaMsZipArchive.cs @@ -0,0 +1,123 @@ +using Sarand.Net.Standard.Base.App; +using Sarand.Net.Standard.Base.Bus; +using Sarand.Net.Standard.Base.Core; +using Sarand.Net.Standard.Base.Utils; +using System; +using System.Collections.ObjectModel; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Text; + +namespace Sarand.Net.Standard.Data.Zip +{ + //======================================================================= + public class SaMsZipArchive : SaErrorStateItem + { + //------------------------------------------------------------------- + // Data members. + private ZipArchive zipArchive; + + //------------------------------------------------------------------- + // Construction. + public SaMsZipArchive () + { + } + protected override void Dispose (bool disposing) + { + if (disposing) + { + if (zipArchive != null) zipArchive.Dispose(); + } + } + + //------------------------------------------------------------------- + // Properties. + + //------------------------------------------------------------------- + // A r c h i v e F i l e + //------------------------------------------------------------------- + public bool OpenArchive (String filePath, ZipArchiveMode mode = ZipArchiveMode.Read) + { + ClearErrorState(); + if (StringUtil.IsEmpty(filePath)) return SetErrorState("Filename must be supplied"); + CloseArchive(); + try + { + zipArchive = ZipFile.OpenRead(filePath);//, mode); + ReadOnlyCollection entries = zipArchive.Entries; + int entryCount = entries.Count; + } + catch (Exception exc) + { + SaLogger.Warn(GetType().Name + ".OpenArchive " + ExceptionUtil.GetLogMessage(exc)); + return SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); + } + return !HasErrorState(); + } + /// Open ZIP archive from data stream. + public bool OpenArchive (Stream stream, ZipArchiveMode mode = ZipArchiveMode.Read, bool leaveOpen = true, Encoding entryNameEncoding = null) + { + ClearErrorState(); + if (entryNameEncoding == null) entryNameEncoding = Encoding.Default; + CloseArchive(); + try + { + zipArchive = new ZipArchive(stream, mode, leaveOpen, entryNameEncoding); + ReadOnlyCollection entries = zipArchive.Entries; + int entryCount = entries.Count; + } + catch (Exception exc) + { + SaLogger.Warn(GetType().Name + ".OpenArchive " + ExceptionUtil.GetLogMessage(exc)); + return SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); + } + return !HasErrorState(); + } + public bool IsArchiveOpen () + { + return (zipArchive != null); + } + /// Close eth ZIP archive. + public bool CloseArchive () + { + ClearErrorState(); + try + { + if (zipArchive != null) zipArchive.Dispose(); + } + catch (Exception exc) + { + SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); + SaLogger.Warn(GetType().Name + ".CloseArchive " + ExceptionUtil.GetLogMessage(exc)); + } + zipArchive = null; + return !HasErrorState(); + } + + //------------------------------------------------------------------- + // F i l e s + //------------------------------------------------------------------- + public MemoryStream ExtractFileToStream (String filename) + { + if (!IsArchiveOpen()) return null; + foreach (ZipArchiveEntry entry in zipArchive.Entries) + { + //SaLogger.Debug(GetType().Name + ".GetFile Entry: " + entry.FullName); + if (entry.FullName.EqualsCI(filename) || entry.Name.EqualsCI(filename)) + { + using (Stream entryStream = entry.Open()) + { + MemoryStream stream = new MemoryStream(); + entryStream.CopyTo(stream); + return stream; + } + } + } + return null; + } + + //------------------------------------------------------------------- + } + //======================================================================= +} diff --git a/SacsStandardData/SacsStandardData.csproj b/SacsStandardData/SacsStandardData.csproj new file mode 100644 index 0000000..99cb6fd --- /dev/null +++ b/SacsStandardData/SacsStandardData.csproj @@ -0,0 +1,21 @@ + + + + netstandard2.1 + Sarand.Net.Standard + + + + + + + + + + + + + + + + diff --git a/SacsStandardDbas/Dbas/Base/DatabaseDefinitionGenerator.cs b/SacsStandardDbas/Dbas/Base/DatabaseDefinitionGenerator.cs index 19b00b8..86e559d 100644 --- a/SacsStandardDbas/Dbas/Base/DatabaseDefinitionGenerator.cs +++ b/SacsStandardDbas/Dbas/Base/DatabaseDefinitionGenerator.cs @@ -507,6 +507,8 @@ namespace Sarand.Net.Standard.Dbas.Base String className = tableDfn.Name + "_Db"; List primaryColumnNames = tableDfn.GetPrimaryColumnNames(); String identityColumnName = tableDfn.Columns.GetIdentityColumnName(); + String identityColumnVariableTypeName = tableDfn.Columns.GetIdentityColumnVariableTypeName(); + String identityColumnCastFromInt64 = (!identityColumnVariableTypeName.EqualsCI("Int64") && !identityColumnVariableTypeName.EqualsCI("long") ? "(" + identityColumnVariableTypeName + ")" : ""); // Class 'using's. List usingNamespaces = new List(config.TableClass.Usings); @@ -690,7 +692,7 @@ namespace Sarand.Net.Standard.Dbas.Base if (!String.IsNullOrEmpty(identityColumnName)) { // Execute single command to insert and query 'Scope_Identity' to retrieve Identity value. - file.WriteLine(tab3 + "_" + identityColumnName + " = Convert.ToInt32(dbCommand.ExecuteScalar());"); + file.WriteLine(tab3 + "_" + identityColumnName + " = " + identityColumnCastFromInt64 + "Convert.ToInt64(dbCommand.ExecuteScalar());"); file.WriteLine(tab3 + "commandSuccess = (_" + identityColumnName + " > 0);"); } else @@ -710,7 +712,7 @@ namespace Sarand.Net.Standard.Dbas.Base { // Retrieve Identity value. file.WriteLine(tab4 + "dbCommand.CommandText = \"SELECT Max(" + identityColumnName + ") FROM \" + TableNameFmt + \";\";"); - file.WriteLine(tab4 + "_" + identityColumnName + " = Convert.ToInt32(dbCommand.ExecuteScalar());"); + file.WriteLine(tab4 + "_" + identityColumnName + " = " + identityColumnCastFromInt64 + "Convert.ToInt64(dbCommand.ExecuteScalar());"); file.WriteLine(tab4 + "commandSuccess = (_" + identityColumnName + " > 0);"); } else diff --git a/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs b/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs index 746a5fe..85d5491 100644 --- a/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs +++ b/SacsStandardDbas/Dbas/Data/SacsDatabaseOdbc.cs @@ -380,7 +380,7 @@ namespace Sarand.Net.Standard.Dbas.Data { if (refresh) ClearTableDfns(); // Only populate table names and/or table schemas where not previously done. - if (tables.Count < 1 || tables.Exists(item => item.Columns.Count < 1)) + if (tables.Count < 1 || tables.Exists(item => !item.HasColumns())) { // Use a single connection for table and schaema population. using (DbConnection dbConnection = CreateConnection(true)) @@ -390,7 +390,7 @@ namespace Sarand.Net.Standard.Dbas.Data PopulateTableNames(dbConnection); foreach (DbDfnTable table in tables) { - if (table.Columns.Count < 1) + if (!table.HasColumns()) { PopulateTableColumns(dbConnection, table); PopulateTableIndices(dbConnection, table);