Saxonite 1.2.11.2
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
# Sarand
|
||||
|
||||
## Common Projects Visual Studio 2019
|
||||
## Common Projects Visual Studio 2022
|
||||
|
||||
### Modules
|
||||
|
||||
* NB All projects upgraded to .Net 6, 28Nov23.
|
||||
* SACS Standard Base
|
||||
* Base class library. .Net Standard 2.1. C#.
|
||||
* SACS Standard Dbas
|
||||
@@ -13,7 +14,7 @@
|
||||
* SACS Standard Mob
|
||||
* Base Mobile application library. .Net Standard 2.1. C#.
|
||||
* SACS Core Web
|
||||
* Base Web application library. .Net Core 3.1. C#.
|
||||
* Base Web application library. [C# .Net 6]
|
||||
* SACS Core Unit Tests
|
||||
* Unit Tests. .Net Core 3.1. C#.
|
||||
* Unit Tests. [C# .Net 6]
|
||||
|
||||
|
||||
+8
-2
@@ -1,7 +1,7 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.31112.23
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.8.34316.72
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardBase", "SacsStandardBase\SacsStandardBase.csproj", "{3A8EE4B3-2335-420B-9619-D1622AF511FA}"
|
||||
EndProject
|
||||
@@ -20,6 +20,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution files", "Solution
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardAccounts", "SacsStandardAccounts\SacsStandardAccounts.csproj", "{C62999E2-1947-4EB7-82D2-A0EDB67D2F10}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SacsStandardProc", "SacsStandardProc\SacsStandardProc.csproj", "{3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -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
|
||||
{3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3988EE9F-FFCD-481A-AF5E-AA7E5DB5A415}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
|
||||
<IsPackable>false</IsPackable>
|
||||
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Sacs.UnitTests.Net.Standard.Base.Utils
|
||||
{
|
||||
[TestClass]
|
||||
public class SerializableUtil_Tester
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
[Serializable]
|
||||
private class TestData
|
||||
{
|
||||
public String stringValue = "String Value";
|
||||
public long longValue = 123456;
|
||||
}
|
||||
[Serializable]
|
||||
private class TestDataA : TestData
|
||||
{
|
||||
public TestDataA()
|
||||
{
|
||||
stringValue = "String Value A";
|
||||
longValue = 654321;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Random random = new Random();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Deep Copy.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SerializableUtil_DeepCopy()
|
||||
{
|
||||
// Clone test data.
|
||||
TestData data = new TestData();
|
||||
TestData data_DeepCopy = SerializableUtil.DeepCopy(data);
|
||||
|
||||
// Verify results.
|
||||
Assert.AreEqual(true, data_DeepCopy is TestData);
|
||||
Assert.AreEqual(data.stringValue, data_DeepCopy.stringValue);
|
||||
Assert.AreEqual(data.longValue, data_DeepCopy.longValue);
|
||||
|
||||
// Clone test data A.
|
||||
TestDataA dataA = new TestDataA();
|
||||
TestDataA dataA_DeepCopy = SerializableUtil.DeepCopy(dataA);
|
||||
|
||||
// Verify results.
|
||||
Assert.AreEqual(true, dataA_DeepCopy is TestData);
|
||||
Assert.AreEqual(true, dataA_DeepCopy is TestDataA);
|
||||
Assert.AreEqual(dataA.stringValue, dataA_DeepCopy.stringValue);
|
||||
Assert.AreEqual(dataA.longValue, dataA_DeepCopy.longValue);
|
||||
Assert.AreNotEqual(data.stringValue, dataA_DeepCopy.stringValue);
|
||||
Assert.AreNotEqual(data.longValue, dataA_DeepCopy.longValue);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Reflection;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
|
||||
namespace Sarand.UnitTests.Core.Base.Utils
|
||||
{
|
||||
[TestClass]
|
||||
public class SysUtil_Tester
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private static readonly String ClassName_GeneratedMemberName_Prefix = "<";
|
||||
private static readonly String ClassName_CompilerGeneratedClass = ClassName_GeneratedMemberName_Prefix + ">c";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Calling code class name.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SysUtil_GetCallerClassName_Test()
|
||||
{
|
||||
// Leading spaces.
|
||||
Assert.AreNotEqual(null, SysUtil.GetCallerClassName());
|
||||
Assert.AreNotEqual("", SysUtil.GetCallerClassName());
|
||||
Assert.AreEqual("SysUtil_Tester", SysUtil.GetCallerClassName());
|
||||
|
||||
// Compiler generated context.
|
||||
Func<string> temp = () => { return SysUtil.GetCallerClassName(); };
|
||||
Assert.AreEqual(ClassName_CompilerGeneratedClass, temp());
|
||||
|
||||
// Anonymous function.
|
||||
Assert.AreEqual(ClassName_CompilerGeneratedClass, ((Func<string>)(() => SysUtil.GetCallerClassName()))());
|
||||
Assert.AreEqual(ClassName_CompilerGeneratedClass, new Func<string>(() => SysUtil.GetCallerClassName())());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Calling code function name.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SysUtil_GetCallerMemberName_Test()
|
||||
{
|
||||
// Leading spaces.
|
||||
Assert.AreNotEqual(null, SysUtil.GetCallerMemberName());
|
||||
Assert.AreNotEqual("", SysUtil.GetCallerMemberName());
|
||||
Assert.AreEqual("SysUtil_GetCallerMemberName_Test", SysUtil.GetCallerMemberName());
|
||||
Assert.AreEqual(nameof(SysUtil_GetCallerMemberName_Test), SysUtil.GetCallerMemberName());
|
||||
Assert.AreEqual(MethodBase.GetCurrentMethod().Name, SysUtil.GetCallerMemberName());
|
||||
|
||||
// Compiler generated context.
|
||||
Func<string> temp = () => { return SysUtil.GetCallerMemberName(); };
|
||||
Assert.AreEqual(MethodBase.GetCurrentMethod().Name, temp());
|
||||
|
||||
// Anonymous function.
|
||||
Assert.AreEqual(MethodBase.GetCurrentMethod().Name, ((Func<string>)(() => SysUtil.GetCallerMemberName()))());
|
||||
Assert.AreEqual(MethodBase.GetCurrentMethod().Name, new Func<string>(() => SysUtil.GetCallerMemberName())());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Calling code file path.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SysUtil_GetCallerFilePath_Test()
|
||||
{
|
||||
// Leading spaces.
|
||||
Assert.AreNotEqual(null, SysUtil.GetCallerFilePath());
|
||||
Assert.AreNotEqual("", SysUtil.GetCallerFilePath());
|
||||
Assert.AreEqual(@"D:\Sarand\Projects\Users\AHoward\VS2022\Common-VS\Workspace\SacsCoreUnitTests\Standard\Base\Utils\SysUtil_Tester.cs", SysUtil.GetCallerFilePath());
|
||||
Assert.AreEqual(true, SysUtil.GetCallerFilePath().EndsWith("SysUtil_Tester.cs"));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Calling code line number.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SysUtil_GetCallerLineNumber_Test()
|
||||
{
|
||||
// Leading spaces.
|
||||
Assert.AreNotEqual(0, SysUtil.GetCallerLineNumber());
|
||||
Assert.AreEqual((new StackFrame(0, true)).GetFileLineNumber(), SysUtil.GetCallerLineNumber());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Calling code file path.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SysUtil_GetCallerClassMethod_Test()
|
||||
{
|
||||
// Leading spaces.
|
||||
Assert.AreNotEqual(null, SysUtil.GetCallerClassMethod());
|
||||
Assert.AreNotEqual("", SysUtil.GetCallerClassMethod());
|
||||
Assert.AreEqual(GetType().Name + "." + MethodBase.GetCurrentMethod().Name, SysUtil.GetCallerClassMethod());
|
||||
Assert.AreEqual(nameof(SysUtil_Tester) + "." + nameof(SysUtil_GetCallerClassMethod_Test), SysUtil.GetCallerClassMethod());
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Calling code file path.
|
||||
//-------------------------------------------------------------------
|
||||
[TestMethod]
|
||||
public void SysUtil_Fn_Test()
|
||||
{
|
||||
// Leading spaces.
|
||||
Assert.AreNotEqual(null, SysUtil.Fn);
|
||||
Assert.AreNotEqual("", SysUtil.Fn);
|
||||
Assert.AreEqual(GetType().Name + "." + MethodBase.GetCurrentMethod().Name, SysUtil.Fn);
|
||||
Assert.AreEqual(nameof(SysUtil_Tester) + "." + nameof(SysUtil_Fn_Test), SysUtil.Fn);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<RootNamespace>Sacs.Net.Core</RootNamespace>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Sacs</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<FrameworkReference Include="Microsoft.AspNetCore.App" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\SacsStandardBase\SacsStandardBase.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.AspNetCore.Routing;
|
||||
using Microsoft.Net.Http.Headers;
|
||||
using Newtonsoft.Json;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Helpers;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.Web;
|
||||
|
||||
namespace Sacs.Web.Components
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaController : Controller
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Protected construction - use derived objects.
|
||||
/// </summary>
|
||||
protected SaController()
|
||||
{
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
private static String ClassName { get; } = nameof(SaController);
|
||||
public DateTime CreatedAt { get; } = DateTime.Now;
|
||||
public bool DebugMode { get; } = SacsSystem.DebugMode;
|
||||
/// <summary>
|
||||
/// Indicate whether session data should be stored by action.
|
||||
/// <para>Any action that might modify the session data must store it.</para>
|
||||
/// <para>Some actions such as scoring a password's complexity don't need to.</para>
|
||||
/// </summary>
|
||||
public virtual bool StoreSessionData { get; protected set; } = true;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Culture.
|
||||
private CultureInfo sessionCulture;
|
||||
private CultureInfo RequestCulture { get { return Request.HttpContext.Features.Get<IRequestCultureFeature>().RequestCulture.Culture ?? CultureInfo.InvariantCulture; } }
|
||||
public CultureInfo SessionCulture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (sessionCulture == null)
|
||||
{
|
||||
sessionCulture = RequestCulture;
|
||||
// ToDo Adjust culture if needed.
|
||||
}
|
||||
return sessionCulture;
|
||||
}
|
||||
}
|
||||
private string LanguageIso2
|
||||
{
|
||||
get
|
||||
{
|
||||
var feature = HttpContext.Features.Get<IRequestCultureFeature>();
|
||||
return feature.RequestCulture.UICulture.TwoLetterISOLanguageName.ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Redirection locations.
|
||||
//-------------------------------------------------------------------
|
||||
public static readonly String ParamName_SessionExpired = "SessionExpired";
|
||||
public enum RedirectLocation
|
||||
{
|
||||
WebAppBase,
|
||||
WebAppHome,
|
||||
WebAppHome_SessionExpired,
|
||||
}
|
||||
public String GetRedirectLocation(RedirectLocation redirectLocation)
|
||||
{
|
||||
string protocol = Request.Scheme;
|
||||
var parameters = new RouteValueDictionary();
|
||||
String homeAction = Url.Action("Index", "Home", parameters, protocol);
|
||||
switch (redirectLocation)
|
||||
{
|
||||
case RedirectLocation.WebAppBase:
|
||||
return Regex.Replace(homeAction, "\\/$", "") + "/";
|
||||
case RedirectLocation.WebAppHome:
|
||||
return homeAction;
|
||||
case RedirectLocation.WebAppHome_SessionExpired:
|
||||
// Set the session expired parameter so that the page can report it.
|
||||
// NB Paramater must have a value to be included in the URL query string.
|
||||
parameters.Add(ParamName_SessionExpired, "1");
|
||||
return homeAction;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Action execution events.
|
||||
//-------------------------------------------------------------------
|
||||
public override void OnActionExecuting(ActionExecutingContext filterContext)
|
||||
{
|
||||
//if (DebugMode) SaLogger.Debug(GetType().Name + ".OnActionExecuting" + (ViewData.Model != null ? " Model: " + ViewData.Model : ""));
|
||||
|
||||
base.OnActionExecuting(filterContext);
|
||||
}
|
||||
public override void OnActionExecuted(ActionExecutedContext filterContext)
|
||||
{
|
||||
//if (DebugMode) SaLogger.Debug(GetType().Name + ".OnActionExecuted" + (ViewData.Model != null ? " Model: " + ViewData.Model : ""));
|
||||
|
||||
base.OnActionExecuted(filterContext);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public static String EncryptParameters(NameValueCollection parameters, String base64IV, String base64Key)
|
||||
{
|
||||
String fn = ClassName + ".EncryptParameters";
|
||||
try
|
||||
{
|
||||
// Copy the list of parameters and sort the keys.
|
||||
NameValueCollection parametersToEncrypt = new NameValueCollection(parameters);
|
||||
String[] paramKeys = parametersToEncrypt.AllKeys;
|
||||
Array.Sort(paramKeys);
|
||||
|
||||
// Serialise parameters as if in a URL query string - so that they can be deserialised in DecryptParameters() below.
|
||||
// Start with a random length parameter name at start of list to obscure the encryption.
|
||||
string queryString = SacsRandomHelper.getRandomLengthNumber(4) + "&";
|
||||
queryString += String.Join("&", paramKeys.Select(a => a + "=" + HttpUtility.UrlEncode(parametersToEncrypt[a])));
|
||||
|
||||
// Encrypt data.
|
||||
String encrypted = SacsEncryptionHelper.Encrypt(queryString, base64IV, base64Key);
|
||||
//if (SacsSystem.DebugMode) SaLogger.Debug(fn + "\n\tData: " + queryString + " \n\tEncrypted: " + encrypted);
|
||||
return encrypted;
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return "";
|
||||
}
|
||||
public static NameValueCollection DecryptParameters(String encrypted, String base64IV, String base64Key)
|
||||
{
|
||||
String fn = ClassName + ".DecryptParameters";
|
||||
try
|
||||
{
|
||||
String queryString = SacsEncryptionHelper.Decrypt(encrypted, base64IV, base64Key);
|
||||
//if (SacsSystem.DebugMode) SaLogger.Debug(fn + " \n\tEncrypted: " + encrypted + "\n\tData: " + queryString);
|
||||
return HttpUtility.ParseQueryString(queryString);
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(fn + " " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return new NameValueCollection();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cookies.
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Retrieve the value from the named request cookie.</summary>
|
||||
public String GetRequestCookie(String key)
|
||||
{
|
||||
if (Request.Cookies.ContainsKey(key))
|
||||
return Request.Cookies[key];
|
||||
return null;
|
||||
}
|
||||
/// <summary>Set the value against the named response cookie.</summary>
|
||||
public void SetResponseCookie(string key, string value, DateTime? expiresAt = null, bool isEssential = false)
|
||||
{
|
||||
CookieOptions options = new CookieOptions();
|
||||
options.HttpOnly = true;
|
||||
options.Secure = true;
|
||||
options.SameSite = Microsoft.AspNetCore.Http.SameSiteMode.Strict;
|
||||
if (expiresAt.HasValue)
|
||||
options.Expires = expiresAt;
|
||||
if (isEssential)
|
||||
options.IsEssential = true;
|
||||
Response.Cookies.Append(key, value, options);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Ajax actions.
|
||||
//-------------------------------------------------------------------
|
||||
protected static readonly Encoding ajaxResponseEncoding = Encoding.UTF8;
|
||||
protected IActionResult GetAjaxResult_GoHome(AjaxResponse_Base responseData)
|
||||
{
|
||||
responseData.SetGoHome();
|
||||
return Json(responseData);
|
||||
}
|
||||
protected IActionResult GetAjaxResult_InvalidSession(AjaxResponse_Base responseData)
|
||||
{
|
||||
responseData.SetGoHome();
|
||||
return Json(responseData);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Response data.
|
||||
// Null values are ignored by JSON serialisation.
|
||||
// - See Saxonite.Net.Core.Web.Base.App.SaxStartup.ConfigureServices()
|
||||
// - Ref. config.services.AddMvc(...).AddJsonOptions(options => { options.JsonSerializerOptions.IgnoreNullValues = true; });
|
||||
//-------------------------------------------------------------------
|
||||
// Base response data - for simple responses.
|
||||
public class AjaxResponse_Base
|
||||
{
|
||||
// Response status.
|
||||
public bool? Success { get; set; } = null;
|
||||
public bool? Error { get; set; } = null;
|
||||
public bool? SessionExpired { get; protected set; } = null;
|
||||
public bool? GoHome { get; protected set; } = null;
|
||||
public AjaxResponse_Base SetSessionExpired(String title, String text)
|
||||
{
|
||||
SessionExpired = true;
|
||||
return SetMessage(title, text);
|
||||
}
|
||||
public AjaxResponse_Base SetGoHome()
|
||||
{
|
||||
GoHome = true;
|
||||
return this;
|
||||
}
|
||||
public AjaxResponse_Base SetGoHome(String title, String text)
|
||||
{
|
||||
GoHome = true;
|
||||
return SetMessage(title, text);
|
||||
}
|
||||
// Message - displays alert popup.
|
||||
public class MessageData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String Text { get; set; }
|
||||
}
|
||||
public MessageData Message { get; private set; }
|
||||
public AjaxResponse_Base SetMessage(String title, String text)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(text))
|
||||
Message = new MessageData() { Title = title, Text = text };
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public class AjaxResponse_Data : AjaxResponse_Base
|
||||
{
|
||||
//---------------------------------------------------------------
|
||||
// Construction.
|
||||
protected AjaxResponse_Data(SaModel model)
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
/// <summary>Item data - Common properties for data items.</summary>
|
||||
public class ItemData_Base
|
||||
{
|
||||
// Common item properties.
|
||||
public String Id { get; set; }
|
||||
public String Notes { get; set; }
|
||||
public String StatusCode { get; set; }
|
||||
public String StatusDesc { get; set; }
|
||||
// Flags for common status values.
|
||||
// Return true or null so that property is not serialised when false.
|
||||
public bool? Awaiting { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Awaiting)) ? true : (bool?)null; } }
|
||||
public bool? Active { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Active)) ? true : (bool?)null; } }
|
||||
public bool? Inactive { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Inactive)) ? true : (bool?)null; } }
|
||||
public bool? Deleted { get { return StatusCode.EqualsCI(SacsSystem.GetStatusCode(SaStatus.Deleted)) ? true : (bool?)null; } }
|
||||
/// <summary>Created on date - YYYYMMDD</summary>
|
||||
public String CreatedOn { get; set; }
|
||||
/// <summary>Created on date - formatted per locale</summary>
|
||||
public String CreatedOnFmt { get; set; }
|
||||
/// <summary>Updated on date - YYYYMMDD</summary>
|
||||
public String UpdatedOn { get; set; }
|
||||
/// <summary>Updated on date - formatted per locale</summary>
|
||||
public String UpdatedOnFmt { get; set; }
|
||||
}
|
||||
/// <summary>Contact Method properties.</summary>
|
||||
public class ContactMethodData
|
||||
{
|
||||
public String Method { get; set; }
|
||||
public String MethodCaption { get; set; }
|
||||
public String Value { get; set; }
|
||||
}
|
||||
/// <summary>Address properties.</summary>
|
||||
public class AddressData : ItemData_Base
|
||||
{
|
||||
public String Line1 { get; set; }
|
||||
public String Line2 { get; set; }
|
||||
public String Line3 { get; set; }
|
||||
public String Town { get; set; }
|
||||
public String RegionIdProvince { get; set; }
|
||||
public String RegionNameProvince { get; set; }
|
||||
public String RegionIdCountry { get; set; }
|
||||
public String RegionNameCountry { get; set; }
|
||||
public String PostalCode { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Item data with label and value.
|
||||
/// </summary>
|
||||
public class ItemLabelValue
|
||||
{
|
||||
public String Label { get; set; }
|
||||
public String Value { get; set; }
|
||||
}
|
||||
/// <summary>
|
||||
/// Item data with just Id and name.
|
||||
/// <para>- Id is String to allow for obfuscated values.</para>
|
||||
/// </summary>
|
||||
public class ItemIdName
|
||||
{
|
||||
public String Id { get; set; }
|
||||
public String Name { get; set; }
|
||||
}
|
||||
/// <summary>Item code and desc values.</summary>
|
||||
public class ItemCodeDesc
|
||||
{
|
||||
public String Code { get; set; }
|
||||
public String Desc { get; set; }
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Form data.
|
||||
public class FormControlValue
|
||||
{
|
||||
public FormControlValue(String controlName, String value, String error)
|
||||
{
|
||||
ControlName = controlName;
|
||||
Value = value;
|
||||
Error = error;
|
||||
}
|
||||
public String ControlName { get; }
|
||||
public String Value { get; set; }
|
||||
public String Error { get; set; }
|
||||
}
|
||||
private readonly Dictionary<String, FormControlValue> controlValues = new Dictionary<String, FormControlValue>();
|
||||
public List<FormControlValue> ControlValues { get { return controlValues.Count > 0 ? controlValues.Values.ToList() : null; } }
|
||||
public void SetControlValue(String controlName, String value, String error = null)
|
||||
{
|
||||
if (controlValues.ContainsKey(controlName))
|
||||
{
|
||||
// Modify existing entry in the list.
|
||||
FormControlValue controlValue = controlValues[controlName];
|
||||
if (value != null) controlValue.Value = value;
|
||||
if (error != null) controlValue.Error = error;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add new control to list.
|
||||
controlValues.Add(controlName, new FormControlValue(controlName, value, error));
|
||||
}
|
||||
}
|
||||
/// <summary>Assign the error to the control by name and return this response data.</summary>
|
||||
public AjaxResponse_Data SetControlError(String controlName, String error)
|
||||
{
|
||||
return SetControlError(controlName, error, this);
|
||||
}
|
||||
/// <summary>
|
||||
/// Assign the error to the control by name and return the specified value.
|
||||
/// <para>- Allows alternative return values to be specified (eg. 'false') to avoid separate return statement in calling routine.</para>
|
||||
/// </summary>
|
||||
public T SetControlError<T>(String controlName, String error, T returnValue)
|
||||
{
|
||||
SetControlValue(controlName, null, error);
|
||||
return returnValue;
|
||||
}
|
||||
public bool HasControlErrors()
|
||||
{
|
||||
foreach (FormControlValue controlValue in controlValues.Values)
|
||||
{
|
||||
if (!StringUtil.IsEmpty(controlValue.Error)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Notification - briefly displays after response received.
|
||||
public class NotificationData
|
||||
{
|
||||
public String Title { get; set; }
|
||||
public String Message { get; set; }
|
||||
}
|
||||
public NotificationData Notification { get; private set; }
|
||||
public AjaxResponse_Data SetNotification(String title, String message)
|
||||
{
|
||||
Notification = new NotificationData() { Title = title, Message = message };
|
||||
return this;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Paged data.
|
||||
public class PagingData
|
||||
{
|
||||
public PagingData(SaModel model) :
|
||||
this(model.Paging.PageNo, model.Paging.PageLength, model.Paging.ItemCount, model.Paging.ItemTotal)
|
||||
{ }
|
||||
public PagingData(uint pageNo, ushort pageLength, ushort itemCount, ulong itemTotal)
|
||||
{
|
||||
PageNo = pageNo;
|
||||
PageLength = pageLength;
|
||||
ItemCount = itemCount;
|
||||
ItemTotal = itemTotal;
|
||||
}
|
||||
public bool Paged { get { return (PageNo > 0 && PageLength > 0 && ItemTotal > PageLength); } }
|
||||
public uint PageNo { get; } = 0;
|
||||
public ushort PageLength { get; } = 0;
|
||||
public uint PageCount { get { return (PageLength > 0 ? (uint)Math.Ceiling((decimal)ItemTotal / PageLength) : 0); } }
|
||||
public ushort ItemCount { get; } = 0;
|
||||
public ulong ItemTotal { get; } = 0;
|
||||
}
|
||||
public PagingData Paging { get; private set; }
|
||||
public void SetPaging(SaModel model)
|
||||
{
|
||||
Paging = new PagingData(model);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using static Sarand.Net.Standard.Base.Bus.SaErrorStateItem;
|
||||
|
||||
namespace Sacs.Web.Components
|
||||
{
|
||||
//=======================================================================
|
||||
public class SaModel
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private readonly List<String> infoMessages = new List<string>();
|
||||
private readonly List<String> warningMessages = new List<string>();
|
||||
private readonly List<String> errorMessages = new List<string>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Protected construction - use derived objects.
|
||||
/// </summary>
|
||||
protected SaModel()
|
||||
{
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
// Properties.
|
||||
public bool DebugMode { get; } = SacsSystem.DebugMode;
|
||||
public bool OK { get { return !HasMessages(); } }
|
||||
public virtual bool ProhibitCache { get; set; } = true;
|
||||
public String PageCaption { get; set; }
|
||||
public bool IncludeGoogleAnalytics { get; set; } = false;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Page configuration.
|
||||
// Views can be registered to avoid multiple inclusions in a page.
|
||||
private HashSet<String> registeredViews = new HashSet<String>(StringComparer.OrdinalIgnoreCase);
|
||||
/// <summary>
|
||||
/// Views can be registered to avoid multiple inclusions in a page.
|
||||
/// <para>Only generate view content if this method returns true.</para>
|
||||
/// </summary>
|
||||
public bool RegisterView(String viewName)
|
||||
{
|
||||
#if DEBUG
|
||||
if (registeredViews.Contains(viewName))
|
||||
SaLogger.Warn(this.GetType().Name + ".RegisterView View already registered: " + viewName);
|
||||
#endif
|
||||
return registeredViews.Add(viewName);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Version parameter for includes.
|
||||
public String HrefVersion
|
||||
{
|
||||
get
|
||||
{
|
||||
DateTime versionDate = SacsSystem.AssemblyBuildAt;
|
||||
if (!DateUtil.IsValid(versionDate) || SacsSystem.DebugMode)
|
||||
versionDate = DateTime.Now;
|
||||
return DateUtil.Format(versionDate, "yyyyMMdd" /*+ (SacsSystem.Debug ? "HHmm" : "")*/);
|
||||
}
|
||||
}
|
||||
// Additional includes.
|
||||
public HashSet<String> AdditionalFiles_CSS { get; set; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
public HashSet<String> AdditionalFiles_JS { get; set; } = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Redirection locations.
|
||||
public class RedirectLocationData
|
||||
{
|
||||
// Properties populated in Controller_Base.OnActionExecuted.
|
||||
public String Base { get; set; }
|
||||
public String Home { get; set; }
|
||||
public String Home_SessionExpired { get; set; }
|
||||
}
|
||||
public RedirectLocationData RedirectLocation { get; } = new RedirectLocationData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Paging properties.
|
||||
public class DataPaging
|
||||
{
|
||||
private DbQuery.Paging paging { get; } = new DbQuery.Paging();
|
||||
public void PopulatePagingTo(DbQuery.Paging resultsPaging)
|
||||
{
|
||||
resultsPaging.PageLength = paging.PageLength;
|
||||
resultsPaging.PageNo = paging.PageNo;
|
||||
}
|
||||
public bool IsPaged { get { return paging.Paged; } }
|
||||
public uint PageNo { get { return paging.PageNo; } set { paging.PageNo = value; } }
|
||||
public String PageNoValue { get { return paging.PageNo.ToString(); } set { paging.PageNo = (uint)StringUtil.ToInt(value); } }
|
||||
public ushort PageLength { get { return paging.PageLength; } set { paging.PageLength = value; } }
|
||||
public String PageLengthValue { get { return paging.PageLength.ToString(); } set { paging.PageLength = (ushort)StringUtil.ToShort(value); } }
|
||||
public uint PageCount { get { return (PageLength > 0 ? (uint)Math.Ceiling((decimal)ItemTotal / paging.PageLength) : 0); } }
|
||||
public ushort ItemCount { get; set; }
|
||||
private ulong itemTotal = 0;
|
||||
public ulong ItemTotal
|
||||
{
|
||||
get { return itemTotal; }
|
||||
set
|
||||
{
|
||||
itemTotal = value;
|
||||
// Check whether the total number of items is less than the current page and reduce page no if needed.
|
||||
if (IsPaged && (PageNo - 1) * PageLength > itemTotal)
|
||||
PageNo = (uint)((itemTotal - 1) / PageLength + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
public DataPaging Paging { get; } = new DataPaging();
|
||||
public void PopulatePagingTo(DbQuery.Paging resultsPaging)
|
||||
{
|
||||
Paging.PopulatePagingTo(resultsPaging);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Messages.
|
||||
//-------------------------------------------------------------------
|
||||
public bool HasMessages()
|
||||
{
|
||||
return infoMessages.Count > 0 || warningMessages.Count > 0 || errorMessages.Count > 0;
|
||||
}
|
||||
public List<String> InfoMessages { get { return new List<string>(infoMessages); } }
|
||||
public List<String> WarningMessages { get { return new List<string>(warningMessages); } }
|
||||
public List<String> ErrorMessages { get { return new List<string>(errorMessages); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Form messages.
|
||||
public void AddInfoMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
infoMessages.Add(message);
|
||||
}
|
||||
public void AddWarningMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
warningMessages.Add(message);
|
||||
}
|
||||
public void AddErrorMessage(String message)
|
||||
{
|
||||
if (StringUtil.IsEmpty(StringUtil.TrimAll(message))) return;
|
||||
errorMessages.Add(message);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Sarand.Net.Standard</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
|
||||
@@ -98,7 +98,9 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
public String DateTimeSeparator { get; set; } = " ";
|
||||
public String TimeFormat { get; set; } = "HH:mm";
|
||||
public DataValue.DataType DataType { get; set; } = DataValue.DataType.String;
|
||||
public bool IsNumeric { get { return DataType == DataValue.DataType.Long || DataType == DataValue.DataType.Double || DataType == DataValue.DataType.Decimal; } }
|
||||
public bool Resizable { get; set; } = true;
|
||||
public bool WrapText { get; set; } = false;
|
||||
public bool Hidden { get; set; } = false;
|
||||
public bool Frozen { get; set; } = false;
|
||||
// Drop-down configuration.
|
||||
@@ -107,12 +109,11 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
public bool ExclusiveValues { get; set; } = true;
|
||||
/// <summary>User entered values (Exclusive=false) are converted if corresponding value found in list.</summary>
|
||||
public bool MatchCase { get; set; } = true;
|
||||
// Edit configuration:
|
||||
// Edit configuration.
|
||||
public int MaxLength { get; set; } = 0;
|
||||
public bool ReadOnly { get; set; } = false;
|
||||
public bool Uppercase { get; set; } = false;
|
||||
public bool Lowercase { get; set; } = false;
|
||||
public bool Numeric { get; set; } = false;
|
||||
public bool Password { get; set; } = false;
|
||||
// Sort attributes.
|
||||
/// <summary>Sort mode. Default: 'On'.</summary>
|
||||
|
||||
@@ -172,6 +172,7 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
/// <summary>Return value interpretted as boolean.</summary>
|
||||
public bool ToBool ()
|
||||
{
|
||||
if (value == null) return false;
|
||||
@@ -190,6 +191,7 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/// <summary>Return explicit boolean value or false for other types.</summary>
|
||||
public bool AsBool ()
|
||||
{
|
||||
// Convert to specific type of data - fails if type is not correct:
|
||||
@@ -369,10 +371,58 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
// Data Value list extension functions.
|
||||
|
||||
public static class DataValueList
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Population.
|
||||
|
||||
/// <summary>Add a String value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, String value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
/// <summary>Add a boolean value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, bool value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
/// <summary>Add an integer value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, int value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
/// <summary>Add a long value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, long value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
/// <summary>Add a double value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, double value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
/// <summary>Add a decimal value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, decimal value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
/// <summary>Add a date time value to the list.</summary>
|
||||
public static void Add(this List<DataValue> values, DateTime value)
|
||||
{
|
||||
values.Add(new DataValue(value));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Conversion.
|
||||
|
||||
/// <summary>Convert all data values to strings.</summary>
|
||||
public static List<String> ToStringList (this List<DataValue> values)
|
||||
{
|
||||
@@ -381,6 +431,7 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
stringValues.Add(values.ToString());
|
||||
return stringValues;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert the data values to raw objects.
|
||||
/// <para>eg. For population to Excel spreadsheet cells.</para>
|
||||
@@ -409,6 +460,7 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Numeric - only with compatible numeric values.
|
||||
|
||||
/// <summary>Minimum numeric value in the list.</summary>
|
||||
public static DataValue GetMinValue (this List<DataValue> values)
|
||||
{
|
||||
@@ -425,6 +477,7 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
}
|
||||
return minValue;
|
||||
}
|
||||
|
||||
/// <summary>Maximum numeric value in the list.</summary>
|
||||
public static DataValue GetMaxValue (this List<DataValue> values)
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ namespace Sarand.Net.Standard.Base.Core
|
||||
// Disposal.
|
||||
~SacsDisposable ()
|
||||
{
|
||||
Dispose(false);
|
||||
Dispose(!disposed);
|
||||
}
|
||||
public void Dispose ()
|
||||
{
|
||||
|
||||
@@ -38,8 +38,20 @@ namespace Sarand.Net.Standard.Base.Helpers
|
||||
public new String PreferredContentType { set { base.PreferredContentType = value; } }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
/// <summary>Excel legacy - xls.</summary>
|
||||
public static readonly String ContentType_Excel_Legacy = "application/vnd.ms-excel";
|
||||
/// <summary>Excel open - xlsx.</summary>
|
||||
public static readonly String ContentType_Excel_Open = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
|
||||
/// <summary>Excel macro enabled - xlsm.</summary>
|
||||
public static readonly String ContentType_Excel_MacroEnabled = "application/vnd.ms-excel.sheet.macroEnabled.12";
|
||||
/// <summary>Excel binary macro enabled - xlsb.</summary>
|
||||
public static readonly String ContentType_Excel_BinaryMacroEnabled = "application/vnd.ms-excel.sheet.binary.macroEnabled.12";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
static String ContentType_Generic = "application/octet-stream";
|
||||
private static readonly List<ContentTypeData> contentTypes;
|
||||
private static FileExtensionContentTypeProvider provider = null;
|
||||
private static readonly HashSet<Sacs.MimeType> allowedMimeTypes_CV = new HashSet<Sacs.MimeType>()
|
||||
@@ -87,8 +99,8 @@ namespace Sarand.Net.Standard.Base.Helpers
|
||||
new ContentTypeData_Internal("docx", "Microsoft Word (OpenXML)", "application/vnd.openxmlformats-officedocument.wordprocessingml.document", Sacs.MimeType.MsDocx),
|
||||
new ContentTypeData_Internal("odt", "OpenDocument text document", "application/vnd.oasis.opendocument.text", Sacs.MimeType.OpenDocText),
|
||||
// Spreadsheets.
|
||||
new ContentTypeData_Internal("xls", "Microsoft Excel", "application/vnd.ms-excel", Sacs.MimeType.MsXls),
|
||||
new ContentTypeData_Internal("xlsx", "Microsoft Excel (OpenXML)", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", Sacs.MimeType.MsXlsx),
|
||||
new ContentTypeData_Internal("xls", "Microsoft Excel", ContentType_Excel_Legacy, Sacs.MimeType.MsXls),
|
||||
new ContentTypeData_Internal("xlsx", "Microsoft Excel (OpenXML)", ContentType_Excel_Open, Sacs.MimeType.MsXlsx),
|
||||
new ContentTypeData_Internal("ods", "OpenDocument spreadsheet document", "application/vnd.oasis.opendocument.spreadsheet", Sacs.MimeType.OpenDocSpreadsheet),
|
||||
// Miscellaneous.
|
||||
new ContentTypeData_Internal("aac", "AAC audio", "audio/aac"),
|
||||
@@ -156,7 +168,7 @@ namespace Sarand.Net.Standard.Base.Helpers
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
/// <summary>Generic content type used for 'unknown' document types.</summary>
|
||||
public static String ContentTypeDefault { get; } = "application/octet-stream";
|
||||
public static String ContentTypeDefault { get; } = ContentType_Generic;
|
||||
/// <summary>Selection of comon content types.</summary>
|
||||
public static List<ContentTypeData> ContentTypes { get { return new List<ContentTypeData>(contentTypes); } }
|
||||
public static FileExtensionContentTypeProvider Provider
|
||||
@@ -223,6 +235,20 @@ namespace Sarand.Net.Standard.Base.Helpers
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
/// <summary>Convert the enumerated Mime to content type.</summary>
|
||||
public static String GetContentTypeFromMimeType(Sacs.MimeType mime)
|
||||
{
|
||||
if (mime == Sacs.MimeType.Unknown) return ContentTypeDefault;
|
||||
ContentTypeData contentTypeData = contentTypes.Find(item => item.Mime.Equals(mime));
|
||||
if (contentTypeData != null)
|
||||
return contentTypeData.ContentType;
|
||||
return ContentTypeDefault;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
// Mime type.
|
||||
//----------------------------------------------------------------------
|
||||
|
||||
/// <summary>Convert the content type to enumerated Mime.</summary>
|
||||
public static Sacs.MimeType GetMimeTypeFromContentType(this String contentType)
|
||||
{
|
||||
|
||||
@@ -1,29 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging.Abstractions;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Tasks;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using static Sarand.Net.Standard.Base.Procs.SaProcess_Base;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Procs
|
||||
{
|
||||
//=======================================================================
|
||||
public interface ISacsProcessNotifier
|
||||
{
|
||||
void OnStartProcess ();
|
||||
void SetProgressInfo (List<String> progressInfo);
|
||||
void OnEndProcess ();
|
||||
}
|
||||
|
||||
//=======================================================================
|
||||
public abstract class SaProcess_Base : SacsDisposable
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Exceptions.
|
||||
[Serializable]
|
||||
public class InProgressException : Exception
|
||||
{
|
||||
public InProgressException() { }
|
||||
public InProgressException(string message) : base(message) { }
|
||||
public InProgressException(string message, Exception inner) : base(message, inner) { }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Process options and groups - for configuration of process to run.
|
||||
// See Sarand.Win.Forms.Utility.SaForm_SelectOptions.
|
||||
public class OptionData
|
||||
{
|
||||
public OptionData (TypeCodeDesc option)
|
||||
public OptionData(TypeCodeDesc option)
|
||||
{
|
||||
Option = option;
|
||||
}
|
||||
@@ -33,7 +41,7 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
}
|
||||
public class GroupData
|
||||
{
|
||||
public GroupData (TypeCodeDesc optionGroup)
|
||||
public GroupData(TypeCodeDesc optionGroup)
|
||||
{
|
||||
OptionGroup = optionGroup;
|
||||
}
|
||||
@@ -55,13 +63,13 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
}
|
||||
public class Config
|
||||
{
|
||||
protected Config ()
|
||||
protected Config()
|
||||
{
|
||||
}
|
||||
/// <summary>Identifies the type of process.</summary>
|
||||
public ProcessType ProcessType { get; set; } = ProcessType.Unknown;
|
||||
/// <summary>Is the process to be run in 'Test' mode.</summary>
|
||||
public bool TestProcess{ get; set; } = SacsSystem.DebugMode;
|
||||
public bool TestProcess { get; set; } = SacsSystem.DebugMode;
|
||||
/// <summary>Process imports data.</summary>
|
||||
public bool Import { get { return ProcessType == ProcessType.ImportData || ProcessType == ProcessType.ImportExportData; } }
|
||||
/// <summary>Process exports data.</summary>
|
||||
@@ -74,28 +82,131 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
public bool Automated { get; set; } = false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Process control definitions.
|
||||
|
||||
public class ProcessMessage
|
||||
{
|
||||
public ProcessMessage(String message, SaMessageLevel level = SaMessageLevel.Info)
|
||||
{
|
||||
this.Message = message;
|
||||
this.Level = level;
|
||||
}
|
||||
public String Message { get; }
|
||||
public SaMessageLevel Level { get; }
|
||||
public int Instances { get; internal set; }
|
||||
}
|
||||
|
||||
private class ProcessControlData
|
||||
{
|
||||
// Interrupt.
|
||||
private class InterruptData
|
||||
{
|
||||
public readonly Object lockable = new object();
|
||||
private bool interrupted = false;
|
||||
public bool Interrupted { get { lock (lockable) { return interrupted; } } set { lock (lockable) { interrupted = value; } } }
|
||||
}
|
||||
private InterruptData interrupt { get; } = new InterruptData();
|
||||
public bool Interrupted { get { return interrupt.Interrupted; } set { interrupt.Interrupted = value; } }
|
||||
|
||||
// Process messages.
|
||||
private class ProcessMessagesData
|
||||
{
|
||||
public readonly Object lockable = new object();
|
||||
public List<ProcessMessage> messages { get; } = new List<ProcessMessage>();
|
||||
}
|
||||
private ProcessMessagesData processMessages { get; } = new ProcessMessagesData();
|
||||
/// <summary>Convert the message levele to one of the 3 values used with Process Messages: Info, Warning, Error.</summary>
|
||||
public static SaMessageLevel GetLevel(SaMessageLevel level)
|
||||
{
|
||||
if (level == SaMessageLevel.Error || level == SaMessageLevel.Fatal || level == SaMessageLevel.Exception)
|
||||
level = SaMessageLevel.Error;
|
||||
else if (level == SaMessageLevel.Warning)
|
||||
level = SaMessageLevel.Warning;
|
||||
else
|
||||
level = SaMessageLevel.Info;
|
||||
return level;
|
||||
}
|
||||
/// <summary>Add a message of the specified level (Info, Warning, Error).</summary>
|
||||
public bool AddProcessMessage(String message, SaMessageLevel level)
|
||||
{
|
||||
message = StringUtil.TrimWhitespace(message);
|
||||
if (StringUtil.IsBlank(message)) return false;
|
||||
level = GetLevel(level);
|
||||
lock (processMessages.lockable)
|
||||
{
|
||||
ProcessMessage procMsg = processMessages.messages.Find(item => item.Message.EqualsCI(message) && item.Level == level);
|
||||
// Duplicate messages increment the 'Instances' value.
|
||||
if (procMsg != null)
|
||||
procMsg.Instances++;
|
||||
// Otherwise add a new message to the list.
|
||||
else processMessages.messages.Add(new ProcessMessage(message, level));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
/// <summary>Are there any message of the specified level (Info, Warning, Error).</summary>
|
||||
public bool HasProcessMessages(SaMessageLevel level)
|
||||
{
|
||||
lock (processMessages.lockable)
|
||||
return processMessages.messages.Exists(item => item.Level == GetLevel(level));
|
||||
}
|
||||
/// <summary>Get the first message of the specified level (Info, Warning, Error).</summary>
|
||||
public String GetProcessMessage(SaMessageLevel level)
|
||||
{
|
||||
lock (processMessages.lockable)
|
||||
return processMessages.messages.Find(item => item.Level == GetLevel(level))?.Message ?? "";
|
||||
}
|
||||
/// <summary>Return all process messages.</summary>
|
||||
public List<ProcessMessage> GetProcessMessages()
|
||||
{
|
||||
List<ProcessMessage> messages = new List<ProcessMessage>();
|
||||
lock (processMessages.lockable)
|
||||
messages.AddRange(processMessages.messages);
|
||||
return messages;
|
||||
}
|
||||
/// <summary>Return all process messages of the specified Level (Info, Warning, Error).</summary>
|
||||
public List<ProcessMessage> GetProcessMessages(SaMessageLevel level)
|
||||
{
|
||||
List<ProcessMessage> messages = new List<ProcessMessage>();
|
||||
lock (processMessages.lockable)
|
||||
messages.AddRange(processMessages.messages.FindAll(item => item.Level == GetLevel(level)));
|
||||
return messages;
|
||||
}
|
||||
/// <summary>Clear process messages.</summary>
|
||||
public void ClearProcessMessages()
|
||||
{
|
||||
lock (processMessages.lockable)
|
||||
processMessages.messages.Clear();
|
||||
}
|
||||
|
||||
// Task control data.
|
||||
private SacsTaskData taskData = null;
|
||||
public SacsTaskData TaskData { get { return taskData; } set { if (taskData != null) taskData.Dispose(); taskData = value; } }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
private String processError = "";
|
||||
private ProcessControlData Control { get; } = new ProcessControlData();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SaProcess_Base (Config config)
|
||||
protected SaProcess_Base(Config config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
// Clear process data to dispose.
|
||||
Control.TaskData = null;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public bool DebugMode { get { return SacsSystem.DebugMode; } }
|
||||
public ISacsProcessNotifier ProcessNotifier { get; set; } = null;
|
||||
public bool Processing { get; protected set; } = false;
|
||||
public bool ProcessEnded { get; protected set; } = false;
|
||||
public DateTime StartedAt { get; private set; } = DateTime.MinValue;
|
||||
@@ -120,56 +231,195 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
public virtual List<StringPair> ProcessingStatistics { get { return new List<StringPair>(); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Run process inline.
|
||||
public bool RunProcess ()
|
||||
// Run process asynchronously.
|
||||
private class AsyncProcessData : SacsDisposable
|
||||
{
|
||||
String fn = GetType().Name+".RunProcess";
|
||||
if (ProcessNotifier == null)
|
||||
throw new NotSupportedException("Process Notifier must be specified");
|
||||
public AsyncProcessData(Task task)
|
||||
{
|
||||
this.Task = task;
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing) { }
|
||||
}
|
||||
public Task Task { get; }
|
||||
}
|
||||
private AsyncProcessData AsyncData { get; set; }
|
||||
public bool IsAsync { get { return AsyncData != null; } }
|
||||
private void ClearAsyncData()
|
||||
{
|
||||
if (AsyncData != null)
|
||||
{
|
||||
lock (AsyncData)
|
||||
{
|
||||
AsyncData.Dispose();
|
||||
AsyncData = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Run the process asynchronously.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
/// <exception cref="InProgressException">If process is already running.</exception>
|
||||
public async void RunAsync()
|
||||
{
|
||||
if (AsyncData != null)
|
||||
throw new InProgressException();
|
||||
Control.TaskData = new SacsTaskData();
|
||||
// Run on separate thread.
|
||||
Task task = new Task(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
// Execute the process.
|
||||
RunProcess();
|
||||
}
|
||||
catch (OperationCanceledException exc)
|
||||
{
|
||||
SaLogger.Warn(exc.GetType().Name + " during asynchronous processing on " + GetType().Name);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Clear processing data.
|
||||
ClearAsyncData();
|
||||
}
|
||||
}, Control.TaskData.CancellationToken);
|
||||
AsyncData = new AsyncProcessData(task);
|
||||
task.Start();
|
||||
await task;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Run process inline.
|
||||
public bool RunProcess()
|
||||
{
|
||||
String fn = GetType().Name + ".RunProcess";
|
||||
// Prepare process.
|
||||
bool runProcess = false;
|
||||
Reset();
|
||||
if (Control.TaskData == null)
|
||||
Control.TaskData = new SacsTaskData();
|
||||
Processing = true;
|
||||
StartedAt = DateTime.Now;
|
||||
|
||||
// Process starting.
|
||||
try
|
||||
{
|
||||
// Notify start of process and log/ignore exceptions.
|
||||
ProcessNotifier.OnStartProcess();
|
||||
InvokeProcessStarting();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " OnStartProcess: " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
|
||||
String msg = exc.GetType().Name + ": " + exc.Message;
|
||||
AddErrorMessage(msg);
|
||||
SaLogger.Error(fn + " ProcessStarting: " + msg + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
|
||||
}
|
||||
|
||||
// Process running.
|
||||
try
|
||||
{
|
||||
// Run process.
|
||||
OnProcessStarting();
|
||||
runProcess = Run();
|
||||
OnProcessEnding();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SetProcessError(exc.GetType().Name + ": " + exc.Message);
|
||||
SaLogger.Error(fn + " " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
|
||||
String msg = exc.GetType().Name + ": " + exc.Message;
|
||||
AddErrorMessage(msg);
|
||||
SaLogger.Error(fn + " " + msg + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Processing completed.
|
||||
FinishedAt = DateTime.Now;
|
||||
Processing = false;
|
||||
ProcessEnded = true;
|
||||
Control.TaskData = null;
|
||||
}
|
||||
|
||||
// Process completed.
|
||||
try
|
||||
{
|
||||
// Notify end of process and log/ignore exceptions.
|
||||
ProcessNotifier.OnEndProcess();
|
||||
// Notify completion of process and log/ignore exceptions.
|
||||
InvokeProcessCompleted();
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " OnEndProcess: " + GetProcessError() + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
|
||||
String msg = exc.GetType().Name + ": " + exc.Message;
|
||||
AddErrorMessage(msg);
|
||||
SaLogger.Error(fn + " ProcessCompleted: " + msg + exc.GetStackEntries(6).Concat("", "\n\tat "), true);
|
||||
}
|
||||
return runProcess;
|
||||
}
|
||||
protected abstract bool Run ();
|
||||
protected virtual void OnProcessStarting () { }
|
||||
protected virtual void OnProcessEnding () { }
|
||||
protected abstract bool Run();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public async Task StopProcessAsync(int timeout = 50)
|
||||
{
|
||||
if (!Processing) return;
|
||||
if (AsyncData != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Cancel the task.
|
||||
Control.TaskData.TriggerCancellation();
|
||||
// Wait for task termination or timeout.
|
||||
if (await Task.WhenAny(AsyncData.Task, Task.Delay(Math.Max(20, Math.Min(1000, timeout)))) != AsyncData.Task)
|
||||
{
|
||||
// Timeout completed before task - force termination.
|
||||
Control.TaskData.ThrowIfCancellationRequested();
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
Control.TaskData = null;
|
||||
ClearAsyncData();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Processing events.
|
||||
|
||||
// Processing Starting.
|
||||
public class ProcessStartingEventArgs : EventArgs { }
|
||||
public event EventHandler<ProcessStartingEventArgs> OnProcessStarting;
|
||||
protected virtual void InvokeProcessStarting()
|
||||
{
|
||||
if (OnProcessStarting != null)
|
||||
{
|
||||
ProcessStartingEventArgs args = new ProcessStartingEventArgs();
|
||||
OnProcessStarting(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
// Process Info Updated.
|
||||
public class ProgressInfoUpdatedEventArgs : EventArgs
|
||||
{
|
||||
public List<String> ProgressInfo { get; } = new List<string>();
|
||||
}
|
||||
public event EventHandler<ProgressInfoUpdatedEventArgs> OnProgressInfoUpdated;
|
||||
protected virtual void InvokeProgressInfoUpdated(List<String> progressInfo)
|
||||
{
|
||||
if (OnProgressInfoUpdated != null)
|
||||
{
|
||||
ProgressInfoUpdatedEventArgs args = new ProgressInfoUpdatedEventArgs();
|
||||
args.ProgressInfo.AddRange(progressInfo);
|
||||
OnProgressInfoUpdated(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
// Processing Completed.
|
||||
public class ProcessCompletedEventArgs : EventArgs { }
|
||||
public event EventHandler<ProcessCompletedEventArgs> OnProcessCompleted;
|
||||
protected virtual void InvokeProcessCompleted()
|
||||
{
|
||||
if (OnProcessCompleted != null)
|
||||
{
|
||||
ProcessCompletedEventArgs args = new ProcessCompletedEventArgs();
|
||||
OnProcessCompleted(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Process control.
|
||||
@@ -177,15 +427,15 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (HasProcessError()) return false;
|
||||
if (isInterrupted) return false;
|
||||
if (HasErrorMessage()) return false;
|
||||
if (Control.Interrupted) return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
private void Reset ()
|
||||
private void Reset()
|
||||
{
|
||||
ClearProcessError();
|
||||
isInterrupted = false;
|
||||
Control.ClearProcessMessages();
|
||||
Control.Interrupted = false;
|
||||
ProcessEnded = false;
|
||||
StartedAt = DateTime.MinValue;
|
||||
FinishedAt = DateTime.MinValue;
|
||||
@@ -193,36 +443,70 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Progress information.
|
||||
protected void SetProgressInfo (String progressInfo)
|
||||
protected void SetProgressInfo(String progressInfo)
|
||||
{
|
||||
SetProgressInfo(StringListUtil.CreateList(progressInfo));
|
||||
}
|
||||
protected void SetProgressInfo (List<String> progressInfo)
|
||||
protected void SetProgressInfo(List<String> progressInfo)
|
||||
{
|
||||
if (ProcessNotifier != null)
|
||||
ProcessNotifier.SetProgressInfo(progressInfo);
|
||||
InvokeProgressInfoUpdated(progressInfo);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Error handling.
|
||||
public bool HasProcessError () { return !StringUtil.IsEmpty(processError); }
|
||||
public String GetProcessError () { return StringUtil.EmptyOnNull(processError); }
|
||||
public void ClearProcessError () { processError = ""; }
|
||||
/// <summary>Record the processing error - always returns false.</summary>
|
||||
public bool SetProcessError (String error)
|
||||
// Process messages.
|
||||
/// <summary>Add a message of the specified level (Info, Warning, Error).</summary>
|
||||
protected void AddMessage(String message, SaMessageLevel level)
|
||||
{
|
||||
processError = StringUtil.EmptyOnNull(error);
|
||||
if (Control.AddProcessMessage(message, level))
|
||||
SaLogger.Log(GetType().Name + " " + message, ProcessControlData.GetLevel(level));
|
||||
}
|
||||
protected void AddInfoMessage(String message)
|
||||
{
|
||||
AddMessage(message, SaMessageLevel.Info);
|
||||
}
|
||||
protected void AddWarningMessage(String message)
|
||||
{
|
||||
AddMessage(message, SaMessageLevel.Warning);
|
||||
}
|
||||
/// <summary>Add the error message and always return false.</summary>
|
||||
protected bool AddErrorMessage(String message)
|
||||
{
|
||||
AddMessage(message, SaMessageLevel.Error);
|
||||
return false;
|
||||
}
|
||||
/// <summary>Are there any error messages.</summary>
|
||||
public bool HasErrorMessage()
|
||||
{
|
||||
return Control.HasProcessMessages(SaMessageLevel.Error);
|
||||
}
|
||||
/// <summary>Get the first error message.</summary>
|
||||
public String GetErrorMessage()
|
||||
{
|
||||
return Control.GetProcessMessage(SaMessageLevel.Error);
|
||||
}
|
||||
/// <summary>Return all process messages.</summary>
|
||||
public List<ProcessMessage> GetProcessMessages()
|
||||
{
|
||||
return Control.GetProcessMessages();
|
||||
}
|
||||
/// <summary>Return all process messages of the specified Level (Info, Warning, Error).</summary>
|
||||
public List<ProcessMessage> GetProcessMessages(SaMessageLevel level)
|
||||
{
|
||||
return Control.GetProcessMessages(level);
|
||||
}
|
||||
/// <summary>Clear process messages.</summary>
|
||||
public void ClearProcessMessages()
|
||||
{
|
||||
Control.ClearProcessMessages();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Interruption.
|
||||
private bool isInterrupted = false;
|
||||
public bool IsInterrupted
|
||||
{
|
||||
get { return isInterrupted; }
|
||||
get { return Control.Interrupted; }
|
||||
}
|
||||
public bool Interrupt ()
|
||||
public bool Interrupt()
|
||||
{
|
||||
if (!config.AllowInterruption)
|
||||
{
|
||||
@@ -230,10 +514,10 @@ namespace Sarand.Net.Standard.Base.Procs
|
||||
return false;
|
||||
}
|
||||
if (config.ConfirmInterruption && !IsInterruptionConfirmed()) return false;
|
||||
isInterrupted = true;
|
||||
Control.Interrupted = true;
|
||||
return true;
|
||||
}
|
||||
protected virtual bool IsInterruptionConfirmed ()
|
||||
protected virtual bool IsInterruptionConfirmed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Sarand.Net.Standard.Base.Tasks
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SacsTaskData (CancellationToken? cancellationToken)
|
||||
public SacsTaskData (CancellationToken? cancellationToken = null)
|
||||
{
|
||||
if (cancellationToken != null)
|
||||
{
|
||||
@@ -49,18 +49,22 @@ namespace Sarand.Net.Standard.Base.Tasks
|
||||
// Properties.
|
||||
public bool Debug { get; set; }
|
||||
|
||||
/// <summary>Token to allow the async request to be cancelled.</summary>
|
||||
public CancellationToken CancellationToken { get; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C a n c e l l a t i o n
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Token to allow the async request to be cancelled.</summary>
|
||||
public CancellationToken CancellationToken { get; }
|
||||
|
||||
/// <summary>Gets whether cancellation has been requested.</summary>
|
||||
public bool IsCancellationRequested { get { return CancellationToken.IsCancellationRequested; } }
|
||||
|
||||
/// <summary>Throws a System.OperationCanceledException if this token has had cancellation requested.</summary>
|
||||
public void ThrowIfCancellationRequested()
|
||||
{
|
||||
CancellationToken.ThrowIfCancellationRequested();
|
||||
}
|
||||
|
||||
/// <summary>Can cancellation be triggered here?</summary>
|
||||
public bool CanBeCancelled { get { return cancellationTokenSource != null; } }
|
||||
public bool TriggerCancellation ()
|
||||
|
||||
@@ -79,7 +79,8 @@ namespace Sarand.Net.Standard.Base.Utils
|
||||
/// </summary>
|
||||
public static SixLabors.ImageSharp.Image LoadImage(byte[] imageData, out IImageFormat format)
|
||||
{
|
||||
var image = Image.Load<Rgba32>(imageData, out format);
|
||||
var image = Image.Load<Rgba32>(imageData);
|
||||
format = Image.DetectFormat(imageData);
|
||||
return image;
|
||||
}
|
||||
|
||||
@@ -90,7 +91,7 @@ namespace Sarand.Net.Standard.Base.Utils
|
||||
{
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
var imageEncoder = image.GetConfiguration().ImageFormatsManager.FindEncoder(imageFormat);
|
||||
var imageEncoder = image.Configuration.ImageFormatsManager.GetEncoder(imageFormat);
|
||||
image.Save(ms, imageEncoder);
|
||||
return ms.ToArray();
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Runtime.Serialization;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
@@ -26,32 +27,24 @@ namespace Sarand.Net.Standard.Base.Utils
|
||||
if (Object.ReferenceEquals(source, null))
|
||||
return default(T);
|
||||
|
||||
IFormatter formatter = new BinaryFormatter();
|
||||
Stream stream = new MemoryStream();
|
||||
using (stream)
|
||||
{
|
||||
formatter.Serialize(stream, source);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return (T)formatter.Deserialize(stream);
|
||||
}
|
||||
// initialize inner objects individually
|
||||
// for example in default constructor some list property initialized with some values,
|
||||
// but in 'source' these items are cleaned -
|
||||
// without ObjectCreationHandling.Replace default constructor values will be added to result
|
||||
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Serialize.
|
||||
public static String Serialize<T>(T source)
|
||||
// Serialize using JSON.
|
||||
public static String ToJson<T>(T source)
|
||||
{
|
||||
if (!typeof(T).IsSerializable) throw new ArgumentException("The type must be serializable.", "source");
|
||||
// Don't serialize a null object, simply return the default for that object
|
||||
if (Object.ReferenceEquals(source, null)) return "";
|
||||
// Serialise to String.
|
||||
IFormatter formatter = new BinaryFormatter();
|
||||
using (Stream stream = new MemoryStream())
|
||||
using (StreamReader streamReader = new StreamReader(stream))
|
||||
{
|
||||
formatter.Serialize(stream, source);
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
return streamReader.ReadToEnd();
|
||||
}
|
||||
// Serialise to JSON String.
|
||||
return JsonConvert.SerializeObject(source);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
@@ -231,7 +231,20 @@ namespace Sarand.Net.Standard.Base.Utils
|
||||
Regex regexMultipleInternal = new Regex("[" + Regex.Escape(new String(trimChars)) + "]{2,}", RegexOptions.None);
|
||||
return regexMultipleInternal.Replace(value, replacement);
|
||||
}
|
||||
|
||||
private static Regex regexWhitespace = new Regex("\\s+", RegexOptions.Compiled);
|
||||
/// <summary>
|
||||
/// Trim all leading and trailling whitespace and replace internal whitespace with a single space.
|
||||
/// </summary>
|
||||
public static String TrimWhitespace(this String value)
|
||||
{
|
||||
return regexWhitespace.Replace(value, " ").Trim();
|
||||
}
|
||||
|
||||
private static Regex regexMultipleSpaces = new Regex("[ ]{2,}", RegexOptions.Compiled);
|
||||
/// <summary>
|
||||
/// Replace multiple spaces with a single space.
|
||||
/// </summary>
|
||||
public static String TrimInternalSpaces(this String value)
|
||||
{
|
||||
return regexMultipleSpaces.Replace(value, " ");
|
||||
@@ -540,6 +553,7 @@ namespace Sarand.Net.Standard.Base.Utils
|
||||
if (value.ToDouble() != 0.0) return true;
|
||||
if (value.Left(1).EqualsCI("Y")) return true;
|
||||
if (value.EqualsCI("True")) return true;
|
||||
if (value.EqualsCI("On")) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,82 @@
|
||||
namespace Sarand.Net.Standard.Base.Utils
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace Sarand.Net.Standard.Base.Utils
|
||||
{
|
||||
//=======================================================================
|
||||
public class SysUtil
|
||||
public static class SysUtil
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
/// <summary>Get calling code's class name.</summary>
|
||||
/// <returns></returns>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static string GetCallerClassName()
|
||||
{
|
||||
try
|
||||
{
|
||||
var stackFrame = new StackTrace().GetFrame(1);
|
||||
var methodInfo = stackFrame.GetMethod();
|
||||
return methodInfo.ReflectedType.Name.TrimWhitespace();
|
||||
}
|
||||
catch (Exception) { }
|
||||
return "";
|
||||
}
|
||||
|
||||
/// <summary>Get calling code's fucntion name.</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static string GetCallerMemberName([CallerMemberName] string memberName = "")
|
||||
{
|
||||
return memberName;
|
||||
}
|
||||
|
||||
/// <summary>Get calling code's file path.</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static string GetCallerFilePath([CallerFilePath] string filePath = "")
|
||||
{
|
||||
return filePath;
|
||||
}
|
||||
|
||||
/// <summary>Get calling code's line number.</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static int GetCallerLineNumber([CallerLineNumber] int lineNumber = 0)
|
||||
{
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
private SysUtil () { }
|
||||
/// <summary>Shortcut to GetCallerClassMethod() - returns [class.method] for calling code.</summary>
|
||||
public static string Fn { get { return GetCallerClassMethod(2); } }
|
||||
|
||||
/// <summary>Return identity of calling method as [class.method].</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static string GetCallerClassMethod(int stackFrameIdx = 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
var stackFrame = new StackTrace().GetFrame(stackFrameIdx);
|
||||
var methodInfo = stackFrame.GetMethod();
|
||||
return (methodInfo.ReflectedType.Name + "." + methodInfo.Name).TrimWhitespace().Trim('.');
|
||||
}
|
||||
catch (Exception) { }
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Return identity of calling method as [class.method:line].</summary>
|
||||
[MethodImpl(MethodImplOptions.NoInlining)]
|
||||
public static string GetCallerClassMethodLine()
|
||||
{
|
||||
try
|
||||
{
|
||||
var stackFrame = new StackTrace().GetFrame(1);
|
||||
var methodInfo = stackFrame.GetMethod();
|
||||
return (methodInfo.ReflectedType.Name + "." + methodInfo.Name + ":" + stackFrame.GetFileLineNumber()).TrimWhitespace().Trim('.');
|
||||
}
|
||||
catch (Exception) { }
|
||||
return "";
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Sarand.Net.Standard</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="CsvHelper" Version="19.0.0" />
|
||||
<PackageReference Include="MailKit" Version="2.11.1" />
|
||||
<PackageReference Include="MailKit" Version="2.15.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.StaticFiles" Version="2.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="2.1.1" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<PackageReference Include="SixLabors.ImageSharp" Version="3.1.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaDbDfnOdbcDriver (String name)
|
||||
public SaDbDfnOdbcDriver(String name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
@@ -25,16 +25,17 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public String Name { get; }
|
||||
public Dictionary<String,String> Attributes { get; } = new Dictionary<String, String>();
|
||||
public Dictionary<String, String> Attributes { get; } = new Dictionary<String, String>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
/// <summary>Add 'Driver' attribute from registry. Fails if driver name not found.</summary>
|
||||
public bool AddDriverConfig ()
|
||||
public bool AddDriverConfig()
|
||||
{
|
||||
if (StringUtil.IsEmpty(Name)) return false;
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
// Retrieve 'Driver' (location of DLL) parameter for this driver:
|
||||
using (RegistryKey localMachineHive = Registry.LocalMachine)
|
||||
using (RegistryKey odbcDriverKey = localMachineHive.OpenSubKey(@"SOFTWARE\ODBC\ODBCINST.INI\" + Name))
|
||||
@@ -47,6 +48,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
catch (Exception) { }
|
||||
return true;
|
||||
|
||||
@@ -22,7 +22,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
protected SacsDatabase (DbmsType dbms, String databaseName, String connectionString)
|
||||
protected SacsDatabase(DbmsType dbms, String databaseName, String connectionString)
|
||||
{
|
||||
DbmsType = dbms;
|
||||
DatabaseName = databaseName;
|
||||
@@ -36,9 +36,9 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
public String DatabaseName { get; }
|
||||
public SelectLockMode SelectLockMode { get; set; } = SelectLockMode.Default;
|
||||
public bool DisplayErrors { get; set; } = true;
|
||||
public abstract void OnConnectionChanged ();
|
||||
public abstract DbConnection CreateConnection (bool forceOdbc = false);
|
||||
public abstract DbDataAdapter CreateDataAdapter ();
|
||||
public abstract void OnConnectionChanged();
|
||||
public abstract DbConnection CreateConnection(bool forceOdbc = false);
|
||||
public abstract DbDataAdapter CreateDataAdapter();
|
||||
// Profile properties.
|
||||
public static String ProfileSection_DbUtilities { get; } = "DbUtilities";
|
||||
public static String ProfileValue_DbExportFile { get; } = "DbExportFile";
|
||||
@@ -57,21 +57,21 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
protected String NextIdTable { get; set; } = "NextId";
|
||||
protected String NextIdColumn_Object { get; set; } = "Object";
|
||||
protected String NextIdColumn_NextId { get; set; } = "NextId";
|
||||
public abstract SysId GetNextId (String objectName, DbUpdateInfo dbUpdateInfo, bool databaseTable = true, String idColumn = "Id");
|
||||
public abstract SysId GetNextId(String objectName, DbUpdateInfo dbUpdateInfo, bool databaseTable = true, String idColumn = "Id");
|
||||
public abstract int GetNextIdFromTable(string objectName, string idColumn = "Id");
|
||||
public abstract bool SetMinNextId (String objectName, SysId id, DbUpdateInfo dbUpdateInfo, bool databaseTable = true, String idColumn = "Id", bool force = false);
|
||||
public abstract bool SetMinNextId(String objectName, SysId id, DbUpdateInfo dbUpdateInfo, bool databaseTable = true, String idColumn = "Id", bool force = false);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// O D B C D r i v e r s
|
||||
//-------------------------------------------------------------------
|
||||
[DllImport("odbccp32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
private static extern bool SQLGetInstalledDriversW (char[] lpszBuf, ushort cbufMax, out ushort pcbBufOut);
|
||||
private static extern bool SQLGetInstalledDriversW(char[] lpszBuf, ushort cbufMax, out ushort pcbBufOut);
|
||||
/// <summary>
|
||||
/// Gets the ODBC driver names from the SQLGetInstalledDrivers function.
|
||||
/// <para>Ref. https://stackoverflow.com/questions/6457973/odbc-driver-list-from-net</para>
|
||||
/// </summary>
|
||||
/// <returns>List of ODBC driver names, if successfull.</returns>
|
||||
public static List<String> GetOdbcDriverNames ()
|
||||
public static List<String> GetOdbcDriverNames()
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -93,13 +93,16 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
catch (Exception) { }
|
||||
try
|
||||
{
|
||||
#pragma warning disable CA1416
|
||||
// Alternatively, use the registry.
|
||||
// Validate platform compatibility
|
||||
using (RegistryKey localMachineHive = Registry.LocalMachine)
|
||||
using (RegistryKey odbcDriversKey = localMachineHive.OpenSubKey(@"SOFTWARE\ODBC\ODBCINST.INI\ODBC Drivers"))
|
||||
{
|
||||
if (odbcDriversKey != null)
|
||||
return new List<String>(odbcDriversKey.GetValueNames()).OrderBy(item => item).ToList();
|
||||
}
|
||||
// Validate platform compatibility
|
||||
// 64-BitConverter machines.
|
||||
using (RegistryKey localMachineHive = Registry.LocalMachine)
|
||||
using (RegistryKey odbcDriversKey = localMachineHive.OpenSubKey(@"SOFTWARE\Wow6432Node\ODBC\ODBCINST.INI\ODBC Drivers"))
|
||||
@@ -107,6 +110,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
if (odbcDriversKey != null)
|
||||
return new List<String>(odbcDriversKey.GetValueNames()).OrderBy(item => item).ToList();
|
||||
}
|
||||
#pragma warning restore CA1416
|
||||
}
|
||||
catch (Exception) { }
|
||||
return new List<String>();
|
||||
@@ -116,13 +120,13 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
// O D B C D a t a S o u r c e s
|
||||
//-------------------------------------------------------------------
|
||||
[DllImport("odbc32.dll")]
|
||||
public static extern int SQLDataSources (int EnvHandle, int Direction, StringBuilder ServerName, int ServerNameBufferLenIn, ref int ServerNameBufferLenOut, StringBuilder Driver, int DriverBufferLenIn, ref int DriverBufferLenOut);
|
||||
public static extern int SQLDataSources(int EnvHandle, int Direction, StringBuilder ServerName, int ServerNameBufferLenIn, ref int ServerNameBufferLenOut, StringBuilder Driver, int DriverBufferLenIn, ref int DriverBufferLenOut);
|
||||
[DllImport("odbc32.dll")]
|
||||
public static extern int SQLAllocEnv (ref int EnvHandle);
|
||||
public static List<SaDbDfnOdbcDataSource> GetOdbcDatasources ()
|
||||
public static extern int SQLAllocEnv(ref int EnvHandle);
|
||||
public static List<SaDbDfnOdbcDataSource> GetOdbcDatasources()
|
||||
{
|
||||
List<SaDbDfnOdbcDataSource> dataSources = new List<SaDbDfnOdbcDataSource>();
|
||||
int envHandle=0;
|
||||
int envHandle = 0;
|
||||
const int SQL_FETCH_NEXT = 1;
|
||||
const int SQL_FETCH_FIRST_SYSTEM = 32;
|
||||
|
||||
@@ -147,7 +151,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
//-------------------------------------------------------------------
|
||||
// Q u e r y D a t a b a s e
|
||||
//-------------------------------------------------------------------
|
||||
public String GetSelectQueryPrefix ()
|
||||
public String GetSelectQueryPrefix()
|
||||
{
|
||||
// Query prefix.
|
||||
switch (SelectLockMode)
|
||||
@@ -180,16 +184,16 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
}
|
||||
return "";
|
||||
}
|
||||
public abstract IDbDataTable ExecuteQuery (String query);
|
||||
public abstract int ExecuteNonQuery (String query);
|
||||
public abstract int ExecuteInsert (String tableName, List<StringPair> columnNameValues);
|
||||
public abstract int ExecuteUpdate (String tableName, List<StringPair> columnNameValues, String filter);
|
||||
public abstract int ExecuteDelete (String tableName, String filter);
|
||||
public abstract IDbDataTable ExecuteQuery(String query);
|
||||
public abstract int ExecuteNonQuery(String query);
|
||||
public abstract int ExecuteInsert(String tableName, List<StringPair> columnNameValues);
|
||||
public abstract int ExecuteUpdate(String tableName, List<StringPair> columnNameValues, String filter);
|
||||
public abstract int ExecuteDelete(String tableName, String filter);
|
||||
/// <summary>
|
||||
/// Add value pair - used to build value lists for insert and update.
|
||||
/// <para>Caters for delimiting text values and uses 'NULL' for empty text values.</para>
|
||||
/// </summary>
|
||||
public static void AddValuePair (List<StringPair> columnNameValues, String columnName, String value, bool delimitString = false)
|
||||
public static void AddValuePair(List<StringPair> columnNameValues, String columnName, String value, bool delimitString = false)
|
||||
{
|
||||
if (delimitString)
|
||||
{
|
||||
@@ -200,42 +204,42 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
columnNameValues.Add(columnName, value);
|
||||
}
|
||||
/// <summary>Add SysId value pair - used to build value lists for insert and update.</summary>
|
||||
public static void AddValuePair (List<StringPair> columnNameValues, String columnName, SysId value)
|
||||
public static void AddValuePair(List<StringPair> columnNameValues, String columnName, SysId value)
|
||||
{
|
||||
columnNameValues.Add(columnName, SysId.ToInt(value).ToString());
|
||||
}
|
||||
/// <summary>Add numeric value pair - used to build value lists for insert and update.</summary>
|
||||
public static void AddValuePair (List<StringPair> columnNameValues, String columnName, long value)
|
||||
public static void AddValuePair(List<StringPair> columnNameValues, String columnName, long value)
|
||||
{
|
||||
columnNameValues.Add(columnName, value.ToString());
|
||||
}
|
||||
/// <summary>Add decimal value pair - used to build value lists for insert and update.</summary>
|
||||
public static void AddValuePair (List<StringPair> columnNameValues, String columnName, decimal value)
|
||||
public static void AddValuePair(List<StringPair> columnNameValues, String columnName, decimal value)
|
||||
{
|
||||
columnNameValues.Add(columnName, value.ToString());
|
||||
}
|
||||
/// <summary>Add date/time value pair - used to build value lists for insert and update.</summary>
|
||||
public static void AddValuePair (List<StringPair> columnNameValues, String columnName, DateTime value)
|
||||
public static void AddValuePair(List<StringPair> columnNameValues, String columnName, DateTime value)
|
||||
{
|
||||
AddValuePair(columnNameValues, columnName, DateUtil.Format(value, "yyyy/MM/dd HH:mm:ss"), true);
|
||||
}
|
||||
// Specific queries.
|
||||
public abstract long GetRowCount (String tableName, String filter);
|
||||
public abstract DataValue GetRowValue (String tableName, String columnName, String filter);
|
||||
public abstract DataValue GetRowValue (String tableName, String columnName, String filter, DbGetValueType getValueType);
|
||||
public abstract long GetRowCount(String tableName, String filter);
|
||||
public abstract DataValue GetRowValue(String tableName, String columnName, String filter);
|
||||
public abstract DataValue GetRowValue(String tableName, String columnName, String filter, DbGetValueType getValueType);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// D a t a b a s e S c h e m a
|
||||
//-------------------------------------------------------------------
|
||||
public abstract List<String> GetTableNames (bool refresh = false);
|
||||
public abstract List<DbDfnTable> GetTableDfns (bool refresh = false);
|
||||
public abstract DbDfnTable GetTableDfn (String name, bool refresh = false);
|
||||
public bool TableExists (String tableName)
|
||||
public abstract List<String> GetTableNames(bool refresh = false);
|
||||
public abstract List<DbDfnTable> GetTableDfns(bool refresh = false);
|
||||
public abstract DbDfnTable GetTableDfn(String name, bool refresh = false);
|
||||
public bool TableExists(String tableName)
|
||||
{
|
||||
if (StringUtil.IsEmpty(tableName)) return false;
|
||||
return GetTableNames().Exists(table => table.EqualsCI(tableName));
|
||||
}
|
||||
public bool ColumnExists (String tableName, String columnName)
|
||||
public bool ColumnExists(String tableName, String columnName)
|
||||
{
|
||||
if (StringUtil.IsEmpty(tableName) || StringUtil.IsEmpty(columnName)) return false;
|
||||
DbDfnTable table = GetTableDfn(tableName);
|
||||
@@ -243,7 +247,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
return table.HasColumnByName(columnName);
|
||||
return false;
|
||||
}
|
||||
public bool IndexExists (String tableName, String indexName)
|
||||
public bool IndexExists(String tableName, String indexName)
|
||||
{
|
||||
if (StringUtil.IsEmpty(tableName) || StringUtil.IsEmpty(indexName)) return false;
|
||||
DbDfnTable table = GetTableDfn(tableName);
|
||||
@@ -263,7 +267,7 @@ namespace Sarand.Net.Standard.Dbas.Base
|
||||
// Logging.
|
||||
public static SaMessageLevel LoggingLevel { get; set; } = SaMessageLevel.None;
|
||||
public static String LoggingPrefix { get; set; } = " ~~~ ";
|
||||
protected static void Log (String fn, String message, SaMessageLevel level = SaMessageLevel.Debug)
|
||||
protected static void Log(String fn, String message, SaMessageLevel level = SaMessageLevel.Debug)
|
||||
{
|
||||
if ((int)level > (int)LoggingLevel) return;
|
||||
SaLogger.Log((fn + "\n\t" + message).Trim(), level);
|
||||
|
||||
@@ -5,7 +5,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -173,10 +173,9 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
// Query records.
|
||||
public override IDbDataTable ExecuteQuery(String query)
|
||||
{
|
||||
String fn = GetType().Name + ".ExecuteQuery";
|
||||
ClearErrorState();
|
||||
DataTable dataTable = null;
|
||||
Log(fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
Log(SysUtil.Fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
try
|
||||
{
|
||||
using (DbConnection dbConnection = CreateConnection())
|
||||
@@ -191,7 +190,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SetErrorState(exc.Message);
|
||||
}
|
||||
return new DbDataTable(dataTable);
|
||||
@@ -200,9 +199,8 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
/// <summary>Execute a non-query statement and return the row count.</summary>
|
||||
public override int ExecuteNonQuery(string query)
|
||||
{
|
||||
String fn = GetType().Name + ".ExecuteNonQuery";
|
||||
ClearErrorState();
|
||||
Log(fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
Log(SysUtil.Fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
using (var dbConnection = CreateConnection())
|
||||
using (var dbCommand = dbConnection.CreateCommand())
|
||||
{
|
||||
@@ -215,7 +213,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SetErrorState(exc.Message);
|
||||
}
|
||||
}
|
||||
@@ -225,13 +223,12 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
/// <summary>Compile and execute an insert statement and return the row count.</summary>
|
||||
public override int ExecuteInsert(String tableName, List<StringPair> columnNameValues)
|
||||
{
|
||||
String fn = GetType().Name + ".ExecuteInsert";
|
||||
ClearErrorState();
|
||||
String query =
|
||||
"INSERT INTO " + tableName + " " +
|
||||
"(" + columnNameValues.GetValues(StringPair.Value.Value1).Concat(", ") + ") " +
|
||||
"VALUES (" + columnNameValues.GetValues(StringPair.Value.Value2).Concat(", ") + ")";
|
||||
Log(fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
Log(SysUtil.Fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
using (var dbConnection = CreateConnection())
|
||||
using (var dbCommand = dbConnection.CreateCommand())
|
||||
{
|
||||
@@ -244,7 +241,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SetErrorState(exc.Message);
|
||||
}
|
||||
}
|
||||
@@ -254,14 +251,13 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
/// <summary>Compile and execute an update statement and return the row count.</summary>
|
||||
public override int ExecuteUpdate(String tableName, List<StringPair> columnNameValues, String filter)
|
||||
{
|
||||
String fn = GetType().Name + ".ExecuteUpdate";
|
||||
ClearErrorState();
|
||||
String query =
|
||||
"UPDATE " + tableName + " " +
|
||||
"SET " + columnNameValues.Concat("=").Concat(", ");
|
||||
if (!StringUtil.IsEmpty(filter))
|
||||
query += (String)" WHERE " + filter;
|
||||
Log(fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
Log(SysUtil.Fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
using (var dbConnection = CreateConnection())
|
||||
using (var dbCommand = dbConnection.CreateCommand())
|
||||
{
|
||||
@@ -274,7 +270,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SetErrorState(exc.Message);
|
||||
}
|
||||
}
|
||||
@@ -284,12 +280,11 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
/// <summary>Compile and execute a delete statement and return the row count.</summary>
|
||||
public override int ExecuteDelete(String tableName, String filter)
|
||||
{
|
||||
String fn = GetType().Name + ".ExecuteDelete";
|
||||
ClearErrorState();
|
||||
String query = "DELETE FROM " + tableName;
|
||||
if (!StringUtil.IsEmpty(filter))
|
||||
query += " WHERE " + filter;
|
||||
Log(fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
Log(SysUtil.Fn, "Query: " + query, SaMessageLevel.Debug);
|
||||
using (var dbConnection = CreateConnection())
|
||||
using (var dbCommand = dbConnection.CreateCommand())
|
||||
{
|
||||
@@ -302,7 +297,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SaLogger.Error(fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SaLogger.Error(SysUtil.Fn + " " + ExceptionUtil.GetLogMessage(exc) + "\n\tQuery: " + query, true);
|
||||
SetErrorState(exc.Message);
|
||||
}
|
||||
}
|
||||
@@ -449,8 +444,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
{
|
||||
if (StringUtil.IsEmpty(tableNameRestriction) && tables.Count > 0) return;
|
||||
if (!StringUtil.IsEmpty(tableNameRestriction) && tables.Exists(item => item.Name.Equals(tableNameRestriction))) return;
|
||||
String fn = GetType().Name + ".PopulateTableNames";
|
||||
if (SacsSystem.DebugMode) SaLogger.Debug(fn + (!StringUtil.IsEmpty(tableNameRestriction) ? " Table: " + tableNameRestriction : " "));
|
||||
if (SacsSystem.DebugMode) SaLogger.Debug(SysUtil.Fn + (!StringUtil.IsEmpty(tableNameRestriction) ? " Table: " + tableNameRestriction : " "));
|
||||
String[] restrictions = new String[] { null, null, tableNameRestriction }; // database, owner, table name, type
|
||||
using (DataTable tableSchema = dbConnection.GetSchema(OdbcMetaDataCollectionNames.Tables, restrictions))
|
||||
{
|
||||
@@ -490,7 +484,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
else if (colName.EqualsCI("REMARKS"))
|
||||
remarks = value;
|
||||
else
|
||||
SaLogger.Warn(fn + " Unrecognised column name: '" + colName + "'");
|
||||
SaLogger.Warn(SysUtil.Fn + " Unrecognised column name: '" + colName + "'");
|
||||
}
|
||||
// TODO Why is Type sometimes "BASE TABLE"?
|
||||
if (!StringUtil.IsEmpty(tableName) && (type.EqualsCI("Table") || type.EqualsCI("Base Table")) && (!schema.EqualsCI("sys") || !tableName.Left(9).EqualsCI("trace_xe_")))
|
||||
@@ -513,8 +507,7 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
//-------------------------------------------------------------------
|
||||
private void PopulateTableColumns(DbConnection dbConnection, DbDfnTable table)
|
||||
{
|
||||
String fn = GetType().Name + ".PopulateTableColumns";
|
||||
if (SacsSystem.DebugMode) SaLogger.Debug(fn + " Table: " + table.Name);
|
||||
if (SacsSystem.DebugMode) SaLogger.Debug(SysUtil.Fn + " Table: " + table.Name);
|
||||
short columnPos = 0;
|
||||
String[] restrictions = new String[] { null, table.Schema, table.Name, null }; // database, owner, table name, column name
|
||||
using (DataTable columnSchema = dbConnection.GetSchema(OdbcMetaDataCollectionNames.Columns, restrictions))
|
||||
@@ -718,7 +711,6 @@ namespace Sarand.Net.Standard.Dbas.Data
|
||||
//-------------------------------------------------------------------
|
||||
private void PopulateTableIndices(DbConnection dbConnection, DbDfnTable table)
|
||||
{
|
||||
String fn = GetType().Name + ".PopulateTableIndices";
|
||||
String[] restrictions = new String[] { null, table.Schema, table.Name }; // database, owner, table name
|
||||
using (DataTable columnSchema = dbConnection.GetSchema(OdbcMetaDataCollectionNames.Indexes, restrictions))
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -41,10 +41,6 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public interface IProcessNotifier : ISacsProcessNotifier
|
||||
{
|
||||
void OnSchemaComparisonItemAdded(SaDbProcess_CompareDatabaseSchemas proc);
|
||||
}
|
||||
public class SchemaComparisonItem
|
||||
{
|
||||
internal SchemaComparisonItem(String tableName, String columnName, int columnPosition, String indexName, String comment)
|
||||
@@ -68,7 +64,6 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
private IProcessNotifier processNotifier = null;
|
||||
private readonly List<SchemaComparisonItem> schemaComparisonItems = new List<SchemaComparisonItem>();
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
@@ -88,13 +83,19 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public override string ProcessDescription { get; } = "Database Schema Comparison";
|
||||
public new IProcessNotifier ProcessNotifier
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Events.
|
||||
|
||||
// Processing Completed.
|
||||
public class SchemaComparisonItemAddedEventArgs : EventArgs { }
|
||||
public event EventHandler<SchemaComparisonItemAddedEventArgs> OnSchemaComparisonItemAdded;
|
||||
protected virtual void InvokeSchemaComparisonItemAdded()
|
||||
{
|
||||
get { return processNotifier; }
|
||||
set
|
||||
if (OnSchemaComparisonItemAdded != null)
|
||||
{
|
||||
processNotifier = value;
|
||||
base.ProcessNotifier = value;
|
||||
SchemaComparisonItemAddedEventArgs args = new SchemaComparisonItemAddedEventArgs();
|
||||
OnSchemaComparisonItemAdded(this, args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,7 +113,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
protected override bool Run()
|
||||
{
|
||||
schemaComparisonItems.Clear();
|
||||
if (config.SourceDatabase == null && config.SourceTables == null) return SetProcessError("Source database must be supplied.");
|
||||
if (config.SourceDatabase == null && config.SourceTables == null) return AddErrorMessage("Source database must be supplied.");
|
||||
|
||||
CompareTables();
|
||||
return OK;
|
||||
@@ -393,7 +394,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
private void AddSchemaComparisonItem(String tableName, String columnName, int position, String indexName, String comment)
|
||||
{
|
||||
schemaComparisonItems.Add(new SchemaComparisonItem(tableName, columnName, position, indexName, comment));
|
||||
if (ProcessNotifier != null) ProcessNotifier.OnSchemaComparisonItemAdded(this);
|
||||
InvokeSchemaComparisonItemAdded();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
}
|
||||
public new class Config : SaProcess_Base.Config
|
||||
{
|
||||
public Config ()
|
||||
public Config()
|
||||
{
|
||||
}
|
||||
public SourceDefinitionType SourceDefinitionType { get; set; }
|
||||
@@ -43,9 +43,6 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public interface IProcessNotifier : ISacsProcessNotifier
|
||||
{
|
||||
}
|
||||
private class Statistics
|
||||
{
|
||||
}
|
||||
@@ -53,17 +50,16 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
private Config config;
|
||||
private IProcessNotifier processNotifier;
|
||||
private readonly List<DbDfnTable> tableDfns = new List<DbDfnTable>();
|
||||
private Statistics stats;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaDbProcess_ConvertDbDefinition (Config config) : base(config)
|
||||
public SaDbProcess_ConvertDbDefinition(Config config) : base(config)
|
||||
{
|
||||
this.config = config;
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
@@ -74,15 +70,6 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
// Properties.
|
||||
public override string ProcessDescription { get; } = "Database Definition Convertor";
|
||||
public new IProcessNotifier ProcessNotifier
|
||||
{
|
||||
get { return processNotifier; }
|
||||
set
|
||||
{
|
||||
processNotifier = value;
|
||||
base.ProcessNotifier = value;
|
||||
}
|
||||
}
|
||||
/// <summary>Processing statistics.</summary>
|
||||
public override List<StringPair> ProcessingStatistics
|
||||
{
|
||||
@@ -102,7 +89,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
// P r o c e s s i n g
|
||||
//-------------------------------------------------------------------
|
||||
protected override bool Run ()
|
||||
protected override bool Run()
|
||||
{
|
||||
// Initialise process.
|
||||
tableDfns.Clear();
|
||||
@@ -115,32 +102,32 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
|
||||
return OK;
|
||||
}
|
||||
protected bool ValidateConfiguration ()
|
||||
protected bool ValidateConfiguration()
|
||||
{
|
||||
// Source file.
|
||||
if (config.SourceDefinitionType <= 0)
|
||||
return SetProcessError("Source definition type must be specified.");
|
||||
return AddErrorMessage("Source definition type must be specified.");
|
||||
if (StringUtil.IsEmpty(config.SourceDefinitionFilePath))
|
||||
return SetProcessError("Source definition file must be specified.");
|
||||
return AddErrorMessage("Source definition file must be specified.");
|
||||
if (!FileUtil.IsFile(config.SourceDefinitionFilePath))
|
||||
return SetProcessError("Source definition file not found.");
|
||||
return AddErrorMessage("Source definition file not found.");
|
||||
|
||||
// Target file.
|
||||
if (config.TargetDefinitionType <= 0)
|
||||
return SetProcessError("Target definition type must be specified.");
|
||||
return AddErrorMessage("Target definition type must be specified.");
|
||||
if (StringUtil.IsEmpty(config.TargetDefinitionFilePath))
|
||||
return SetProcessError("Target definition file must be specified.");
|
||||
return AddErrorMessage("Target definition file must be specified.");
|
||||
if (!DirectoryUtil.DirectoryExists(DirectoryUtil.GetDirectoryName(config.TargetDefinitionFilePath)))
|
||||
return SetProcessError("Target folder not found.");
|
||||
return AddErrorMessage("Target folder not found.");
|
||||
|
||||
if (config.SourceDefinitionFilePath.EqualsCI(config.TargetDefinitionFilePath))
|
||||
return SetProcessError("Target file must not be the same as the source file.");
|
||||
return AddErrorMessage("Target file must not be the same as the source file.");
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
private bool ConvertCppDatabaseDefinition ()
|
||||
private bool ConvertCppDatabaseDefinition()
|
||||
{
|
||||
if (!OK) return false;
|
||||
|
||||
@@ -169,7 +156,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
}
|
||||
private class SourceDefinition_Params
|
||||
{
|
||||
protected SourceDefinition_Params () { }
|
||||
protected SourceDefinition_Params() { }
|
||||
public int LineNumber { get; set; } = -1;
|
||||
public int TableIdx { get; set; } = -1;
|
||||
public int ColumnIdx { get; set; } = -1;
|
||||
@@ -186,7 +173,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
public Dictionary<StringPair, ColumnData> ColumnMap { get; } = new Dictionary<StringPair, ColumnData>();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
private bool ExtractDatabaseDefinition ()
|
||||
private bool ExtractDatabaseDefinition()
|
||||
{
|
||||
if (!OK) return false;
|
||||
|
||||
@@ -245,7 +232,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
file.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { SaLogger.Warn(ExceptionUtil.GetLogMessage(exc)); SetProcessError(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
catch (Exception exc) { SaLogger.Warn(ExceptionUtil.GetLogMessage(exc)); AddErrorMessage(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
|
||||
return OK;
|
||||
}
|
||||
@@ -253,7 +240,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
// C + + C o d e S o u r c e
|
||||
//-------------------------------------------------------------------
|
||||
private readonly Dictionary<int,String> cppColumnDataTypes = new Dictionary<int, string>()
|
||||
private readonly Dictionary<int, String> cppColumnDataTypes = new Dictionary<int, string>()
|
||||
{
|
||||
{ 1, "VarChar" },
|
||||
{ -7, "Bit" },
|
||||
@@ -265,7 +252,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
{ 8, "Double" },
|
||||
{ 93, "DateTime" }
|
||||
};
|
||||
private bool ExtractDatabaseDefinitionLine_CppCode (SourceDefinition_Params_CppCode sourceDfnParams, String line)
|
||||
private bool ExtractDatabaseDefinitionLine_CppCode(SourceDefinition_Params_CppCode sourceDfnParams, String line)
|
||||
{
|
||||
if (!OK) return false;
|
||||
|
||||
@@ -276,7 +263,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
{
|
||||
// Table enum start.
|
||||
if (sourceDfnParams.TablesEnumFound)
|
||||
return SetProcessError("Found multiple table enums at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Found multiple table enums at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
sourceDfnParams.TablesEnumFound = true;
|
||||
sourceDfnParams.InTablesEnum = true;
|
||||
return OK;
|
||||
@@ -289,13 +276,13 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
else if (!line.ContainsCI("eSaDbTblUnknown"))
|
||||
{
|
||||
if (!line.ContainsCI("eSaDbTbl"))
|
||||
return SetProcessError("Invalid table definition on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Invalid table definition on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
// Extract table name.
|
||||
String tableName = line.ReplaceAll("eSaDbTbl","").ReplaceAll(",","");
|
||||
String tableName = line.ReplaceAll("eSaDbTbl", "").ReplaceAll(",", "");
|
||||
if (StringUtil.IsEmpty(tableName))
|
||||
return SetProcessError("Blank table name on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Blank table name on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (tableDfns.Exists(item => item.Name.EqualsCI(tableName)))
|
||||
return SetProcessError("Duplicate table name on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Duplicate table name on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
// Add this table to the list.
|
||||
sourceDfnParams.TableIdx++;
|
||||
//SaLogger.Debug("Table #" + sourceDfnParams.TableIdx + ": " + tableName);
|
||||
@@ -310,7 +297,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
{
|
||||
// Column enum start.
|
||||
if (sourceDfnParams.ColumnsEnumFound)
|
||||
return SetProcessError("Found multiple columns enums at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Found multiple columns enums at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
sourceDfnParams.ColumnsEnumFound = true;
|
||||
sourceDfnParams.InColumnsEnum = true;
|
||||
return OK;
|
||||
@@ -323,7 +310,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
else if (!line.ContainsCI("eSaDbColUnknown"))
|
||||
{
|
||||
if (!line.ContainsCI("eSaDbCol"))
|
||||
return SetProcessError("Invalid column definition on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Invalid column definition on line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
// Column definitions:
|
||||
// eSaDbColUnknown = -1,
|
||||
// #define eSaDbColVendorType_ListID (eSaDbColumn)4101
|
||||
@@ -345,7 +332,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
// Split table and column names on Underscore.
|
||||
String[] tableColumnNameParts = tableColumnName.Split('_');
|
||||
if (tableColumnNameParts.Length != 2)
|
||||
return SetProcessError("Invalid column definition on line (missing underscore?) " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Invalid column definition on line (missing underscore?) " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
sourceDfnParams.ColumnIdx++;
|
||||
String tableName = tableColumnNameParts[0];
|
||||
String columnName = tableColumnNameParts[1];
|
||||
@@ -360,7 +347,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
{
|
||||
// Column definitions start.
|
||||
if (sourceDfnParams.ColumnsDfnsFound)
|
||||
return SetProcessError("Found multiple column definitions at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
return AddErrorMessage("Found multiple column definitions at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
sourceDfnParams.ColumnsDfnsFound = true;
|
||||
sourceDfnParams.InColumnsDfns = true;
|
||||
sourceDfnParams.ColumnIdx = -1;
|
||||
@@ -388,40 +375,40 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
// eTime = 93 SQL_C_TYPE_TIMESTAMP
|
||||
foreach (String columnDfnDataRaw in line.Split(new String[] { "}," }, StringSplitOptions.RemoveEmptyEntries))
|
||||
{
|
||||
String columnDfnData = columnDfnDataRaw.ReplaceAll("{","").TrimAll();
|
||||
String columnDfnData = columnDfnDataRaw.ReplaceAll("{", "").TrimAll();
|
||||
//SaLogger.Debug("Column dfn: " + columnDfnData);
|
||||
String[] columnDfnParts = columnDfnData.Split(',');
|
||||
if (columnDfnParts.Length != 4) return SetProcessError("Invalid column definition (expecting 4 parts) at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (columnDfnParts.Length != 4) return AddErrorMessage("Invalid column definition (expecting 4 parts) at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
String tableIdxRaw = columnDfnParts[0].TrimAll();
|
||||
int tableIdx = StringUtil.ToInt(tableIdxRaw);
|
||||
String columnName = columnDfnParts[1].TrimAll().ReplaceAll("\"","");
|
||||
String columnName = columnDfnParts[1].TrimAll().ReplaceAll("\"", "");
|
||||
String dataTypeRaw = columnDfnParts[2].TrimAll();
|
||||
int dataType = StringUtil.ToInt(dataTypeRaw);
|
||||
String columnLengthRaw = columnDfnParts[3].TrimAll();
|
||||
int columnLength = StringUtil.ToInt(columnLengthRaw);
|
||||
if (!tableIdxRaw.IsNumeric()) return SetProcessError("Invalid table index in column definition (" + tableIdxRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (StringUtil.IsEmpty(columnName)) return SetProcessError("Blank name in column definition at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (!dataTypeRaw.IsNumeric(true) || !cppColumnDataTypes.ContainsKey(dataType)) return SetProcessError("Invalid data type in column definition (" + dataTypeRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (!columnLengthRaw.IsNumeric()) return SetProcessError("Invalid column length in column definition (" + columnLengthRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (!tableIdxRaw.IsNumeric()) return AddErrorMessage("Invalid table index in column definition (" + tableIdxRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (StringUtil.IsEmpty(columnName)) return AddErrorMessage("Blank name in column definition at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (!dataTypeRaw.IsNumeric(true) || !cppColumnDataTypes.ContainsKey(dataType)) return AddErrorMessage("Invalid data type in column definition (" + dataTypeRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (!columnLengthRaw.IsNumeric()) return AddErrorMessage("Invalid column length in column definition (" + columnLengthRaw + ") at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
// Table definition.
|
||||
String tableName = sourceDfnParams.TableMap.Values.ToList().Find(item => item.TableIdx == tableIdx)?.TableName ?? "";
|
||||
if (StringUtil.IsEmpty(tableName)) return SetProcessError("Unable to identify table name for Table idx " + tableIdx + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (StringUtil.IsEmpty(tableName)) return AddErrorMessage("Unable to identify table name for Table idx " + tableIdx + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
DbDfnTable tableDfn = tableDfns.GetTableByName(tableName);
|
||||
if (tableDfn == null) return SetProcessError("Unable to retrieve table definition for Table name " + tableName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (tableDfn == null) return AddErrorMessage("Unable to retrieve table definition for Table name " + tableName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
// Column data.
|
||||
sourceDfnParams.ColumnIdx++;
|
||||
ColumnData columnData = sourceDfnParams.ColumnMap.Values.ToList().Find(item => item.TableName.EqualsCI(tableName) && item.ColumnIdx == sourceDfnParams.ColumnIdx);
|
||||
if (columnData == null) return SetProcessError("Unable to column data for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (columnData.ColumnName.EqualsCI(columnName)) return SetProcessError("Inconsistent column name for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (columnData == null) return AddErrorMessage("Unable to column data for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (columnData.ColumnName.EqualsCI(columnName)) return AddErrorMessage("Inconsistent column name for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
// Column definition.
|
||||
DbDfnColumn columnDfn = new DbDfnColumn()
|
||||
{
|
||||
Table = tableName,
|
||||
Name = columnName,
|
||||
DataType = EnumUtil.ParseEnum(cppColumnDataTypes.GetValue(dataType,""),DbColumnDataType.Unknown),
|
||||
DataType = EnumUtil.ParseEnum(cppColumnDataTypes.GetValue(dataType, ""), DbColumnDataType.Unknown),
|
||||
Size = columnLength
|
||||
};
|
||||
if (columnDfn.DataType < 0) return SetProcessError("Invalid data type for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
if (columnDfn.DataType < 0) return AddErrorMessage("Invalid data type for table " + tableName + " and column " + columnName + " at line " + sourceDfnParams.LineNumber + ": " + line + ".");
|
||||
tableDfn.AddColumn(columnDfn);
|
||||
}
|
||||
return OK;
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
//-------------------------------------------------------------------
|
||||
public List<DbDfnTable> ConvertXmlToTables(String xmlSchemaData)
|
||||
{
|
||||
ClearProcessError();
|
||||
ClearProcessMessages();
|
||||
String fn = GetType().Name + ".ConvertXmlToTables";
|
||||
Dictionary<String, DbDfnTable> tables = new Dictionary<String, DbDfnTable>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
@@ -169,7 +169,7 @@ namespace Sarand.Net.Standard.Dbas.Proc
|
||||
}
|
||||
catch (Exception exc)
|
||||
{
|
||||
SetProcessError(exc.GetErrorStateMessage());
|
||||
AddErrorMessage(exc.GetErrorStateMessage());
|
||||
SaLogger.Warn(fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -3,7 +3,6 @@ using Sarand.Net.Standard.Dbas.Data;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data.Common;
|
||||
using System.Data.Odbc;
|
||||
using Microsoft.Data.SqlClient;
|
||||
using System.Linq;
|
||||
using Sarand.Net.Standard.Base.Dbas;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Sarand.Net.Standard</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Data.SqlClient" Version="2.1.2" />
|
||||
<PackageReference Include="Microsoft.Win32.Registry" Version="5.0.0" />
|
||||
<PackageReference Include="System.Data.Odbc" Version="5.0.0" />
|
||||
<PackageReference Include="System.Data.Odbc" Version="8.0.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Templates
|
||||
{
|
||||
base.OnRemoved(view);
|
||||
}
|
||||
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
|
||||
protected override void OnChildRemoved (Element child)
|
||||
{
|
||||
base.OnChildRemoved(child);
|
||||
|
||||
@@ -66,6 +66,7 @@ namespace Sarand.Net.Standard.Mobile.Forms.Panels
|
||||
{
|
||||
base.OnChildAdded(child);
|
||||
}
|
||||
[Obsolete("OnChildRemoved(Element) is obsolete as of version 4.8.0. Please use OnChildRemoved(Element, int) instead.")]
|
||||
protected override void OnChildRemoved (Element child)
|
||||
{
|
||||
base.OnChildRemoved(child);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Sarand.Net.Standard</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.6.1" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2012" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.8.1" />
|
||||
<PackageReference Include="Xamarin.Forms" Version="5.0.0.2622" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
//=======================================================================
|
||||
public static class ExcelHelper
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Validate worksheet name.
|
||||
/// <para>Worksheet names cannot:</para>
|
||||
/// <para>- Be blank.</para>
|
||||
/// <para>- Contain more than 31 characters.</para>
|
||||
/// <para>- Contain any of the following characters: / \ ? * : [ ]</para>
|
||||
/// <para>- For example, 02/17/2016 would not be a valid worksheet name, but 02-17-2016 would work fine.</para>
|
||||
/// <para>- Begin or end with an apostrophe ('), but they can be used in between text or numbers in a name.</para>
|
||||
/// <para>- Be named "History". This is a reserved word Excel uses internally.</para>
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns></returns>
|
||||
public static bool IsValidSheetName(String name)
|
||||
{
|
||||
if (Base.Utils.StringUtil.IsBlank(name)) return false;
|
||||
if (name.Length > 31) return false;
|
||||
if (Regex.IsMatch(name, "[/\\\\?*:[\\]]")) return false;
|
||||
if (name.StartsWith("'") || name.EndsWith("'")) return false;
|
||||
if (name.EqualsCI("History")) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
}
|
||||
@@ -140,7 +140,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
Yellow = 6,
|
||||
Pink = 7,
|
||||
Magenta = 7,
|
||||
Turqoise = 8,
|
||||
Turquoise = 8,
|
||||
Cyan = 8,
|
||||
DarkRed = 9,
|
||||
Green = 10,
|
||||
@@ -151,7 +151,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
Gray25 = 15,
|
||||
Gray50 = 16,
|
||||
SkyBlue = 33,
|
||||
LightTurqoise = 34,
|
||||
LightTurquoise = 34,
|
||||
LightGreen = 35,
|
||||
LightYellow = 36,
|
||||
PaleBlue = 37,
|
||||
|
||||
@@ -4,6 +4,10 @@ using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Bus;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using NPOI.SS.UserModel;
|
||||
using NPOI.SS.Formula.Functions;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
@@ -16,24 +20,24 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
//=======================================================================
|
||||
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 uint ColFromPos { get; set; } = 0;
|
||||
public uint ColToPos { get; set; } = 0;
|
||||
public uint RowFromPos { get; set; } = 0;
|
||||
public uint RowToPos { get; set; } = 0;
|
||||
public SaMsExcelRange() { }
|
||||
public SaMsExcelRange(uint colPos, uint rowPos)
|
||||
{
|
||||
ColFrom = colPos;
|
||||
ColTo = colPos;
|
||||
RowFrom = rowPos;
|
||||
RowTo = rowPos;
|
||||
ColFromPos = colPos;
|
||||
ColToPos = colPos;
|
||||
RowFromPos = rowPos;
|
||||
RowToPos = rowPos;
|
||||
}
|
||||
public SaMsExcelRange(uint colPosFrom, uint rowPosFrom, uint colPosTo, uint rowPosTo)
|
||||
{
|
||||
ColFrom = colPosFrom;
|
||||
ColTo = colPosTo;
|
||||
RowFrom = rowPosFrom;
|
||||
RowTo = rowPosTo;
|
||||
ColFromPos = colPosFrom;
|
||||
ColToPos = colPosTo;
|
||||
RowFromPos = rowPosFrom;
|
||||
RowToPos = rowPosTo;
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
@@ -78,17 +82,29 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
//=======================================================================
|
||||
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;
|
||||
/// <summary>Cell font colour index, ref. XlColorIndex</summary>
|
||||
public SaXlColourIndex InteriorColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? InteriorColour { get; set; } = null;
|
||||
// Heading configuration.
|
||||
/// <summary>Pixels per cm. Default 43. Min 10, max 100.</summary>
|
||||
public double ColumnWidthPixelsPerCm { get; set; } = 43.0;
|
||||
/// <summary>First heading column position (from 1). Default 1. Must be > 0.</summary>
|
||||
public uint FirstHeadingColPos { get; set; } = 1;
|
||||
/// <summary>First heading row position (from 1). Default 1. Must be > 0.</summary>
|
||||
public uint FirstHeadingRowPos { get; set; } = 1;
|
||||
/// <summary>First data row position. Reset by SetColumnHeadings().</summary>
|
||||
public uint FirstDataRowPos { get; set; } = 2;
|
||||
/// <summary>Freeze column position - cell in first data row. 0 = don't freeze.</summary>
|
||||
public uint FreezeColPos { get; set; } = 0;
|
||||
/// <summary>Font attributes. Default Arial 9 bold.</summary>
|
||||
public SaMsExcelFontAttr FontAttr { get; } = new SaMsExcelFontAttr() { Name = "Arial", HeightInPoints = 9, Bold = true };
|
||||
/// <summary>Whether to wrap column header cells.</summary>
|
||||
public bool HeadingTextWrap { get; set; } = false;
|
||||
/// <summary>Cell vertical alignment. XlVAlign.xlTop, xlCenter, xlBottom, xlJustify, xlDistributed etc.</summary>
|
||||
public short? VerticalAlignment { get; set; } = null;
|
||||
/// <summary>Cell foreground colour index, ref. XlColorIndex</summary>
|
||||
public SaXlColourIndex ForegroundColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell foreground RGB colour value, ref. XlRgbColor. Overrides foreground colour index if changed from default value.</summary>
|
||||
public int? ForegroundColourRGB { get; set; } = null;
|
||||
/// <summary>Cell background colour index, ref. XlColorIndex</summary>
|
||||
public SaXlColourIndex BackgroundColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
public SaXlBorderWeight BorderWeight { get; set; } = SaXlBorderWeight.NotSpecified;
|
||||
public bool SetColumnWidths { get; set; } = true;
|
||||
public bool SetColumnAlignment { get; set; } = true;
|
||||
@@ -147,29 +163,55 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
public class SaMsExcelFontAttr
|
||||
{
|
||||
/// <summary>Font name. Arial etc.</summary>
|
||||
public String FontName { get; set; } = String.Empty;
|
||||
public String Name { get; set; } = String.Empty;
|
||||
/// <summary>Font style. Regular etc.</summary>
|
||||
public String FontStyle { get; set; } = String.Empty;
|
||||
public short? FontSize { get; set; } = null;
|
||||
public double? HeightInPoints { get; set; } = null;
|
||||
/// <summary>Font colour index, ref. XlColorIndex.</summary>
|
||||
public SaXlColourIndex FontColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Font RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? FontColor { get; set; } = null;
|
||||
public SaXlColourIndex ColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Font RGB colour value, ref. XlRgbColor.</summary>
|
||||
public int? ColourRGB { 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? Outline { get; set; } = null;
|
||||
public bool? Shadow { get; set; } = null;
|
||||
public SaXlUnderlineStyle? Underline { get; set; } = null;
|
||||
public void CopyFrom(SaMsExcelFontAttr fontAttr)
|
||||
{
|
||||
Name = fontAttr.Name;
|
||||
FontStyle = fontAttr.FontStyle;
|
||||
HeightInPoints = fontAttr.HeightInPoints;
|
||||
ColourIndex = fontAttr.ColourIndex;
|
||||
ColourRGB = fontAttr.ColourRGB;
|
||||
Bold = fontAttr.Bold;
|
||||
Strikethrough = fontAttr.Strikethrough;
|
||||
Superscript = fontAttr.Superscript;
|
||||
Subscript = fontAttr.Subscript;
|
||||
Outline = fontAttr.Outline;
|
||||
Shadow = fontAttr.Shadow;
|
||||
Underline = fontAttr.Underline;
|
||||
}
|
||||
public bool IsSpecified()
|
||||
{
|
||||
if (HeightInPoints != null && HeightInPoints >= SaMsSpreadsheet.FontHeightInPointsMin && HeightInPoints <= SaMsSpreadsheet.FontHeightInPointsMax) return true;
|
||||
if (ColourRGB != null || ColourIndex != SaXlColourIndex.NotSpecified) return true;
|
||||
if ((Bold ?? false) || (Strikethrough ?? false) || (Superscript ?? false) || (Subscript ?? false) || (Outline ?? false) || (Shadow ?? false) || (Underline != null)) return true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
//=======================================================================
|
||||
public class SaMsExcelItemAttr : SaMsExcelFontAttr
|
||||
/// <summary>
|
||||
/// Style attributes.
|
||||
/// </summary>
|
||||
public class SaMsExcelStyleAttr
|
||||
{
|
||||
// Item attributes.
|
||||
public SaMsExcelFontAttr FontAttr { get; } = new SaMsExcelFontAttr();
|
||||
// Attributes that are changed from their default (generally null) are set against the specified range.
|
||||
/// <summary>Cell data format. "@"=Text etc.</summary>
|
||||
public String NumberFormat { get; set; } = String.Empty;
|
||||
public String DataFormat { get; set; } = String.Empty;
|
||||
/// <summary>Cell horizontal alignment. XlHAlign.xlHAlignLeft, xlHAlignCenter, xlHAlignRight etc.</summary>
|
||||
public short? HorizontalAlignment { get; set; } = null;
|
||||
/// <summary>Cell indentation. Tabbed - left, right or distributed alignment [0 to 6]</summary>
|
||||
@@ -180,16 +222,16 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
public bool? WrapText { get; set; } = null;
|
||||
/// <summary>Whether cells are merged.</summary>
|
||||
public bool? MergeCells { get; set; } = null;
|
||||
/// <summary>Font colour index, ref. XlColorIndex. Black = 1 etc.</summary>
|
||||
public SaXlColourIndex InteriorColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? InteriorColour { get; set; } = null;
|
||||
/// <summary>Cell pattern, ref. XlPattern. xlSolid etc.</summary>
|
||||
/// <summary>Font pattern foreground colour index, ref. XlColorIndex. Black = 1 etc.</summary>
|
||||
public SaXlColourIndex ForegroundColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell pattern foreground RGB colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? ForegroundColourRGB { get; set; } = null;
|
||||
/// <summary>Cell pattern, ref. XlPattern. xlSolid etc. NB Defaults to Solid if foreground colour specified.</summary>
|
||||
public SaXlPattern InteriorPattern { get; set; } = SaXlPattern.NotSpecified;
|
||||
/// <summary>Cell pattern colour index, ref. XlColorIndex. xlAutomatic etc.</summary>
|
||||
public SaXlColourIndex InteriorPatternColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell pattern RBG Colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? InteriorPatternColour { get; set; } = null;
|
||||
/// <summary>Cell pattern background colour index, ref. XlColorIndex. xlAutomatic etc.</summary>
|
||||
public SaXlColourIndex BackgroundColourIndex { get; set; } = SaXlColourIndex.NotSpecified;
|
||||
/// <summary>Cell pattern background RBG Colour value, ref. XlRgbColor. Overrides colour index if changed from default value.</summary>
|
||||
public int? BackgroundPatternColour { get; set; } = null;
|
||||
// Borders.
|
||||
public SaMsExcelBorderAttr BorderLeft { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeLeft);
|
||||
public SaMsExcelBorderAttr BorderTop { get; } = new SaMsExcelBorderAttr(XlBordersIndex.xlEdgeTop);
|
||||
@@ -201,12 +243,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
get
|
||||
{
|
||||
List<SaMsExcelBorderAttr> borders = new List<SaMsExcelBorderAttr>();
|
||||
borders.Add(BorderLeft);
|
||||
borders.Add(BorderTop);
|
||||
borders.Add(BorderRight);
|
||||
borders.Add(BorderBottom);
|
||||
return borders;
|
||||
return new List<SaMsExcelBorderAttr> { BorderLeft, BorderTop, BorderRight, BorderBottom };
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,9 +252,12 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
//-------------------------------------------------------------------
|
||||
// Definitions.
|
||||
public static int FontSizeMin { get; } = 4;
|
||||
public static int FontSizeMax { get; } = 48;
|
||||
public static double FontHeightInPointsMin { get; } = 4;
|
||||
public static double FontHeightInPointsMax { get; } = 48;
|
||||
public static int NullColour { get; } = 0x4a4d4120; /* AFX_RFX_LONG_PSEUDO_NULL */
|
||||
public const String Msg_NotSupported = "Not Supported";
|
||||
public const String Msg_WorkbookNotOpen = "Workbook is not open";
|
||||
public const String Msg_WorksheetNotOpen = "Worksheet is not open";
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Data members.
|
||||
@@ -235,37 +275,55 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k b o o k
|
||||
//-------------------------------------------------------------------
|
||||
// Workbook.
|
||||
|
||||
public abstract bool IsWorkbookValid();
|
||||
public abstract bool CreateWorkbook();
|
||||
public abstract bool OpenWorkbook(String filePath);
|
||||
/// <summary>Cleanse workbook - remove unreferenced styles etc.</summary>
|
||||
public abstract bool CleanseWorkbook();
|
||||
public abstract bool SaveDocument(String filePath, int fileFormat = (int)SaXlFileFormat.Default /* Default: XlFileFormat.xlOpenXMLWorkbook */, bool bAutomaticallyOverwrite = false);
|
||||
public abstract bool CloseWorkbook();
|
||||
public abstract byte[] GetDocumentData();
|
||||
// Default style.
|
||||
public abstract void ApplyDefaultStyle(SaMsExcelStyleAttr attr);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Is the current worksheet valid.</summary>
|
||||
public abstract bool IsWorksheetValid();
|
||||
// Worksheets.
|
||||
|
||||
/// <summary>Number of worksheets in the workbook.</summary>
|
||||
public abstract uint WorksheetCount { get; }
|
||||
/// <summary>Set the worksheets in the workbook - sheets are added or removed to match the value.</summary>
|
||||
public abstract bool SetWorksheetCount(int worksheetCount);
|
||||
/// <summary>Names of worksheets in the workbook.</summary>
|
||||
public abstract List<String> WorksheetNames { get; }
|
||||
|
||||
/// <summary>Add a worksheet to the workbook.</summary>
|
||||
public abstract bool AddWorksheet(String name);
|
||||
/// <summary>Remove the nth worksheet - position from 1.</summary>
|
||||
public abstract bool RemoveWorksheet(uint worksheetPos);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet.
|
||||
|
||||
/// <summary>Open the nth worksheet - position from 1.</summary>
|
||||
public abstract bool OpenWorksheet(uint worksheetPos);
|
||||
/// <summary>Open the worksheet with the specified name.</summary>
|
||||
public abstract bool OpenWorksheet(String name);
|
||||
/// <summary>Close the current worksheet.</summary>
|
||||
public abstract bool CloseWorksheet();
|
||||
|
||||
/// <summary>Is the current worksheet valid.</summary>
|
||||
public abstract bool IsWorksheetValid();
|
||||
|
||||
/// <summary>Get the position of the current worksheet. 0 = not open.</summary>
|
||||
public abstract uint WorksheetPos { get; }
|
||||
/// <summary>Get the name of the current worksheet.</summary>
|
||||
public abstract String WorksheetName { get; set; }
|
||||
|
||||
/// <summary>Set the default attributes for the entire worksheet</summary>
|
||||
public abstract bool SetWorksheetAttr(SaMsExcelItemAttr attr);
|
||||
/// <summary>Close the current worksheet.</summary>
|
||||
public abstract bool CloseWorksheet();
|
||||
public abstract bool SetWorksheetAttr(SaMsExcelStyleAttr attr);
|
||||
|
||||
// Worksheet Page Setup.
|
||||
/// <summary>Configure the Page Setup properties.</summary>
|
||||
public abstract bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig);
|
||||
@@ -273,110 +331,175 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
public abstract bool SetPageBreak(uint colPos, uint rowPos);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
public abstract uint GetActiveColPos();
|
||||
// Columns.
|
||||
|
||||
public abstract uint ActiveColPos { get; }
|
||||
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<DataValue> GetRowDataValues(uint rowPos, int maxColumns = 0);
|
||||
// Rows.
|
||||
|
||||
public abstract uint FirstRowPos { get; }
|
||||
public abstract uint LastRowPos { get; }
|
||||
public abstract uint ActiveRowPos { get; }
|
||||
public abstract List<DataValue> GetRowValues(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
|
||||
//-------------------------------------------------------------------
|
||||
// Cells.
|
||||
|
||||
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<Object> values);
|
||||
public abstract bool SetRangeFormulas(SaMsExcelRange range, List<Object> values);
|
||||
public abstract String GetCellText(uint colPos, uint rowPos, bool trimWhitespace = true);
|
||||
public abstract DataValue GetCellValue(uint colPos, uint rowPos);
|
||||
|
||||
public abstract bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelStyleAttr attr = null);
|
||||
public abstract bool SetCellValue(uint colPos, uint rowPos, DataValue value, SaMsExcelStyleAttr attr = null);
|
||||
|
||||
/// <summary>Set cell formulas across a row - override if more efficient method available.</summary>
|
||||
public virtual bool SetRowFormulas(uint colPosStart, uint rowPos, List<String> values)
|
||||
{
|
||||
for (uint colPos = Math.Max(1, colPosStart); colPos <= values.Count; colPos++)
|
||||
SetCellFormula(colPos, rowPos, values[(int)(colPos - 1)]);
|
||||
return !HasErrorState();
|
||||
}
|
||||
/// <summary>Set cell values across a row - override if more efficient method available.</summary>
|
||||
public virtual bool SetRowValues(uint colPosStart, uint rowPos, List<DataValue> values)
|
||||
{
|
||||
for (uint colPos = Math.Max(1, colPosStart); colPos <= values.Count; colPos++)
|
||||
SetCellValue(colPos, rowPos, values[(int)(colPos - 1)]);
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set cell formulas across a range of cells - override if more efficient logic available.
|
||||
/// <para>- Values will wrap if more cells to fill than values.</para>
|
||||
public virtual bool SetRangeFormulas(SaMsExcelRange range, List<String> values)
|
||||
{
|
||||
if (values.IsEmpty()) return SetErrorState(SysUtil.Fn + " No values supplied");
|
||||
int valueIdx = 0;
|
||||
for (uint colPos = Math.Max(1, range.ColFromPos); colPos <= range.ColToPos; colPos++)
|
||||
{
|
||||
for (uint rowPos = Math.Max(1, range.RowFromPos); rowPos <= range.RowToPos; rowPos++)
|
||||
{
|
||||
// Wrap values if more cells to fill.
|
||||
if (valueIdx >= values.Count)
|
||||
valueIdx = 0;
|
||||
SetCellFormula(colPos, rowPos, values[valueIdx++]);
|
||||
}
|
||||
}
|
||||
return !HasErrorState();
|
||||
}
|
||||
/// <summary>
|
||||
/// Set cell values across a range of cells - override if more efficient logic available.
|
||||
/// <para>- Values will wrap if more cells to fill than values.</para>
|
||||
public virtual bool SetRangeValues(SaMsExcelRange range, List<DataValue> values)
|
||||
{
|
||||
if (values.IsEmpty()) return SetErrorState(SysUtil.Fn + " No values supplied");
|
||||
int valueIdx = 0;
|
||||
for (uint colPos = Math.Max(1, range.ColFromPos); colPos <= range.ColToPos; colPos++)
|
||||
{
|
||||
for (uint rowPos = Math.Max(1, range.RowFromPos); rowPos <= range.RowToPos; rowPos++)
|
||||
{
|
||||
// Wrap values if more cells to fill.
|
||||
if (valueIdx >= values.Count)
|
||||
valueIdx = 0;
|
||||
SetCellValue(colPos, rowPos, values[valueIdx++]);
|
||||
}
|
||||
}
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Populate headings.
|
||||
public bool SetColumnHeadings(List<ColumnDfn> columns, SaMsExcelColumnHeading_Config config)
|
||||
public bool SetColumnHeadings(List<ColumnDfn> columns, SaMsExcelColumnHeading_Config headingConfig)
|
||||
{
|
||||
ClearErrorState();
|
||||
double columnWidthPixelsPerCm = Math.Min(100.0, Math.Max(10.0, config.ColumnWidthPixelsPerCm));
|
||||
uint firstHeadingRow = (uint)Math.Max(1, config.FirstHeadingRow);
|
||||
double columnWidthPixelsPerCm = Math.Min(100.0, Math.Max(10.0, headingConfig.ColumnWidthPixelsPerCm));
|
||||
uint firstHeadingRowPos = (uint)Math.Max(1, headingConfig.FirstHeadingRowPos);
|
||||
// Assume only a single header row.
|
||||
headingConfig.FirstDataRowPos = firstHeadingRowPos + 1;
|
||||
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)
|
||||
SaMsExcelStyleAttr attrHdrDefault = new SaMsExcelStyleAttr();
|
||||
attrHdrDefault.FontAttr.CopyFrom(headingConfig.FontAttr);
|
||||
attrHdrDefault.WrapText = headingConfig.HeadingTextWrap ? true : null;
|
||||
attrHdrDefault.VerticalAlignment = headingConfig.VerticalAlignment;
|
||||
attrHdrDefault.ForegroundColourIndex = headingConfig.ForegroundColourIndex;
|
||||
attrHdrDefault.BackgroundColourIndex = headingConfig.BackgroundColourIndex;
|
||||
if (headingConfig.ForegroundColourRGB != null)
|
||||
attrHdrDefault.ForegroundColourRGB = headingConfig.ForegroundColourRGB;
|
||||
if (headingConfig.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;
|
||||
attrHdrDefault.BorderLeft.Weight = headingConfig.BorderWeight;
|
||||
attrHdrDefault.BorderTop.Weight = headingConfig.BorderWeight;
|
||||
attrHdrDefault.BorderRight.Weight = headingConfig.BorderWeight;
|
||||
attrHdrDefault.BorderBottom.Weight = headingConfig.BorderWeight;
|
||||
}
|
||||
SaMsExcelRange rangeHeadings = new SaMsExcelRange(config.FirstHeadingColumn, firstHeadingRow, (uint)(config.FirstHeadingColumn + columns.Count - 1), firstHeadingRow);
|
||||
SaMsExcelRange rangeHeadings = new SaMsExcelRange(headingConfig.FirstHeadingColPos, firstHeadingRowPos, (uint)(headingConfig.FirstHeadingColPos + columns.Count - 1), firstHeadingRowPos);
|
||||
SetRangeAttr(rangeHeadings, attrHdrDefault);
|
||||
|
||||
// Set default column attributes.
|
||||
bool defaultColumnAttributesPopulated = false;
|
||||
SaMsExcelItemAttr attrColDefault = new SaMsExcelItemAttr();
|
||||
if (config.SetColumnAlignment)
|
||||
SaMsExcelStyleAttr attrColDefault = new SaMsExcelStyleAttr();
|
||||
if (headingConfig.SetColumnAlignment)
|
||||
{
|
||||
attrColDefault.HorizontalAlignment = (short)XlHAlign.xlHAlignLeft;
|
||||
defaultColumnAttributesPopulated = true;
|
||||
}
|
||||
if (config.SetColumnDataTypeFormat)
|
||||
if (headingConfig.SetColumnDataTypeFormat)
|
||||
{
|
||||
attrColDefault.NumberFormat = "@"; // '@' = 'Text' format.
|
||||
attrColDefault.DataFormat = "@"; // '@' = 'Text' format.
|
||||
defaultColumnAttributesPopulated = true;
|
||||
}
|
||||
if (defaultColumnAttributesPopulated)
|
||||
{
|
||||
SaMsExcelRange rangeColumns = new SaMsExcelRange(config.FirstHeadingColumn, 0, (uint)(config.FirstHeadingColumn + columns.Count - 1), 0);
|
||||
SaMsExcelRange rangeColumns = new SaMsExcelRange(headingConfig.FirstHeadingColPos, 0, (uint)(headingConfig.FirstHeadingColPos + columns.Count - 1), 0);
|
||||
SetRangeAttr(rangeColumns, attrColDefault);
|
||||
}
|
||||
|
||||
// Populate column headings and specific styles.
|
||||
List<Object> values = new List<Object>();
|
||||
// Populate column styling and headings.
|
||||
List<DataValue> columnHeadings = new List<DataValue>();
|
||||
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);
|
||||
uint colPos = (uint)(Math.Max(1, headingConfig.FirstHeadingColPos) + columnIdx);
|
||||
SaMsExcelRange range = new SaMsExcelRange(colPos, firstHeadingRowPos);
|
||||
|
||||
// Specific heading cell attributes - none supported as yet.
|
||||
// Specific heading cell attributes.
|
||||
bool headingCellHasSpecificAttr = false;
|
||||
SaMsExcelItemAttr attrHdr = new SaMsExcelItemAttr();
|
||||
SaMsExcelStyleAttr attrHdr = new SaMsExcelStyleAttr();
|
||||
if (headingCellHasSpecificAttr)
|
||||
SetRangeAttr(range, attrHdr);
|
||||
|
||||
// Column width and caption:
|
||||
if (config.SetColumnWidths) SetColWidth(col, column.Width / columnWidthPixelsPerCm, SaExcelLogicalUnit.Cm);
|
||||
values.Add(column.Caption);
|
||||
if (headingConfig.SetColumnWidths) SetColWidth(colPos, column.Width * 1.5 / columnWidthPixelsPerCm, SaExcelLogicalUnit.Cm);
|
||||
columnHeadings.Add(column.Caption);
|
||||
|
||||
// Column attributes:
|
||||
bool columnHasSpecificAttributes = false;
|
||||
SaMsExcelItemAttr attrCol = new SaMsExcelItemAttr();
|
||||
if (config.SetColumnAlignment && column.Alignment != ColumnAlignment.Left && column.Alignment != ColumnAlignment.Default)
|
||||
bool columnHasSpecificStyle = false;
|
||||
SaMsExcelStyleAttr attrCol = new SaMsExcelStyleAttr();
|
||||
if (headingConfig.SetColumnAlignment && column.Alignment != ColumnAlignment.Left && column.Alignment != ColumnAlignment.Default)
|
||||
{
|
||||
columnHasSpecificAttributes = true;
|
||||
columnHasSpecificStyle = 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)
|
||||
if (column.WrapText)
|
||||
{
|
||||
columnHasSpecificAttributes = true;
|
||||
columnHasSpecificStyle = true;
|
||||
attrCol.WrapText = true;
|
||||
}
|
||||
if (headingConfig.SetColumnDataTypeFormat && column.DataType != DataValue.DataType.String)
|
||||
{
|
||||
columnHasSpecificStyle = true;
|
||||
if (column.DataType == DataValue.DataType.Long || column.DataType == DataValue.DataType.Double || column.DataType == DataValue.DataType.Decimal)
|
||||
{
|
||||
// Numeric format: "#,##0.00"
|
||||
@@ -388,63 +511,66 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
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;
|
||||
attrCol.DataFormat = 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;
|
||||
else if (column.DataType == DataValue.DataType.Date) attrCol.DataFormat = headingConfig.CellFormatDate;
|
||||
else if (column.DataType == DataValue.DataType.Time) attrCol.DataFormat = headingConfig.CellFormatTime;
|
||||
else if (column.DataType == DataValue.DataType.DateTime) attrCol.DataFormat = headingConfig.CellFormatDate + headingConfig.CellFormatDateTimeDelim + headingConfig.CellFormatTime;
|
||||
}
|
||||
if (columnHasSpecificAttributes)
|
||||
SetRangeAttr(new SaMsExcelRange(col, 0), attrCol);
|
||||
if (columnHasSpecificStyle)
|
||||
SetRangeAttr(new SaMsExcelRange(colPos, 0), attrCol);
|
||||
// Freeze the window below if a colmn has been specified:
|
||||
if (config.FreezeColumn > 0) FreezePanes(config.FreezeColumn, firstHeadingRow + 1);
|
||||
if (headingConfig.FreezeColPos > 0) FreezePanes(headingConfig.FreezeColPos, firstHeadingRowPos + 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));
|
||||
SetRowValues(headingConfig.FirstHeadingColPos, firstHeadingRowPos, columnHeadings);
|
||||
|
||||
// Auto fit header row if text is wrapped:
|
||||
if (headingConfig.HeadingTextWrap)
|
||||
AutoFitRows(rangeHeadings);
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetColumnHeadings", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public abstract bool SetRangeAttr(SaMsExcelRange range, SaMsExcelItemAttr attr);
|
||||
public abstract bool SetRangeAttr(SaMsExcelRange range, SaMsExcelStyleAttr attr);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Add image to sheet.
|
||||
public abstract bool InsertImage(SaMsExcelImage_Config imageConfig);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Freeze sheet at specified cell.</summary>
|
||||
public abstract bool FreezePanes(uint colPos, uint rowPos);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public abstract bool AutoFit(SaMsExcelRange range);
|
||||
/// <summary>Auto-fit row heights to contents.</summary>
|
||||
public abstract bool AutoFitRows(SaMsExcelRange range);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>Select range of cells.</summary>
|
||||
public abstract bool SelectRange(SaMsExcelRange range);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Utilities.
|
||||
|
||||
/// <summary>
|
||||
/// Convert cell range to Id.
|
||||
/// <para>- Not fixed: "A9:AB34"</para>
|
||||
/// <para>- Fixed cols: "$A9:$AB34"</para>
|
||||
/// <para>- Fixed rows: "A$9:AB$34"</para>
|
||||
/// <para>- Fixed: "$A$9:$AB$34"</para>
|
||||
/// </summary>
|
||||
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);
|
||||
return GetColumnIdPrefix(range.ColFromPos, fixedCols) + GetRowIdSuffix(range.RowFromPos, fixedRows) + ":" + GetColumnIdPrefix(range.ColToPos, fixedCols) + GetRowIdSuffix(range.RowToPos, fixedRows);
|
||||
}
|
||||
public static String GetColumnPrefix(uint colPos)
|
||||
|
||||
/// <summary>
|
||||
/// Convert column position to Id prefix. 1=A,2=B,3=C...26=Z,27=AA,28=AB etc.
|
||||
/// <para>- Fixed prefixes with '$'.</para>
|
||||
/// </summary>
|
||||
public static String GetColumnIdPrefix(uint colPos, bool fixedCol = false)
|
||||
{
|
||||
// 1=A,2=B,3=C...26=Z,27=AA,28=AB etc
|
||||
uint dividend = colPos;
|
||||
string columnName = String.Empty;
|
||||
uint modulo = 0;
|
||||
@@ -454,35 +580,51 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
|
||||
dividend = (uint)((dividend - modulo) / 26);
|
||||
}
|
||||
return columnName;
|
||||
return (fixedCol ? "$" : "") + columnName;
|
||||
}
|
||||
public static int GetIndexForCol(String column)
|
||||
|
||||
/// <summary>Convert column Id to position. A=1,B=2,C=3...Z=26,AA=27 etc.</summary>
|
||||
public static int GetPosForColId(String colId)
|
||||
{
|
||||
// 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];
|
||||
colId = StringUtil.TrimWhitespace(StringUtil.OnBlank(colId)).ToUpper();
|
||||
if (!colId.Matches(new Regex("[A-Z]+")))
|
||||
{
|
||||
SaLogger.Warn(SysUtil.Fn + " Invalid column Id supplied: '" + colId + "'");
|
||||
return -1;
|
||||
}
|
||||
int col = (colId[0] - 'A');
|
||||
if (colId.Length > 1)
|
||||
col = ((colId[1] - 'A') * 26) + (colId[0] - 'A');
|
||||
return col;
|
||||
}
|
||||
|
||||
/// <summary>Column Id - To reference entire column: A:A,B:A,C:A...Z:Z,AA:AA etc.</summary>
|
||||
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);
|
||||
return GetColumnIdPrefix(colPos) + ":" + GetColumnIdPrefix(colPos);
|
||||
}
|
||||
public static String GetRowSuffix(uint rowPos)
|
||||
|
||||
/// <summary>
|
||||
/// Convert row pos to id suffix. 1=1,2=2,3=3...26=26,27=27,28=28 etc.
|
||||
/// <para>- Fixed prefixes with '$'.</para>
|
||||
/// </summary>
|
||||
public static String GetRowIdSuffix(uint rowPos, bool fixedRow = false)
|
||||
{
|
||||
// 1,2,3...26,27,28 etc
|
||||
return (rowPos > 0 ? rowPos.ToString() : "");
|
||||
return (rowPos > 0 ? (fixedRow ? "$" : "") + rowPos.ToString() : "");
|
||||
}
|
||||
|
||||
/// <summary>Row id - To reference entire row: 1:1,2:2,3:3 etc.</summary>
|
||||
public static String GetRowId(uint rowPos)
|
||||
{
|
||||
// To reference entire row: 1:1,2:2,3:3 etc
|
||||
return GetRowSuffix(rowPos) + ":" + GetRowSuffix(rowPos);
|
||||
return GetRowIdSuffix(rowPos) + ":" + GetRowIdSuffix(rowPos);
|
||||
}
|
||||
|
||||
/// <summary>Convert cell by column and row positions to Id.</summary>
|
||||
public static String GetCellId(uint colPos, uint rowPos)
|
||||
{
|
||||
return GetColumnPrefix(colPos) + GetRowSuffix(rowPos);
|
||||
return GetColumnIdPrefix(colPos) + GetRowIdSuffix(rowPos);
|
||||
}
|
||||
|
||||
public static DateTime ExtractDate(String value)
|
||||
{
|
||||
DateTime date = DateTime.MinValue;
|
||||
@@ -502,7 +644,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
//-------------------------------------------------------------------
|
||||
public static double PointsPerInch { get; } = 72;
|
||||
public static double PixelsPerInch { get; } = 96;
|
||||
public static double CmsPerInch { get; } = 2.54f;
|
||||
public static double CmsPerInch { get; } = 2.54;
|
||||
public double ConvertLength(double fLength, SaExcelLogicalUnit eUnitFrom, SaExcelLogicalUnit eUnitTo, bool bVertical)
|
||||
{
|
||||
// Convert length to points:
|
||||
@@ -559,7 +701,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
//-------------------------------------------------------------------
|
||||
protected void HandleException(String fn, Exception exc)
|
||||
{
|
||||
SaLogger.Error(GetType().Name + "." + fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
SaLogger.Error(fn + " " + ExceptionUtil.GetLogMessage(exc));
|
||||
SetErrorState("Problems were encountered interfacing to Excel - " + ExceptionUtil.GetErrorStateMessage(exc));
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
/// <summary>Style properties retrieved directly from spreadsheet xml data.</summary>
|
||||
public class SaMsExcelStyle
|
||||
{
|
||||
public SaMsExcelStyle () { }
|
||||
public SaMsExcelStyle() { }
|
||||
public int NumFmtId { get; set; }
|
||||
public int FontId { get; set; }
|
||||
public int FillId { get; set; }
|
||||
@@ -51,7 +51,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
internal SaMsXmlDocument StylesDoc { get; set; }
|
||||
internal uint WorksheetCount { get; set; }
|
||||
internal uint ActiveSheetPos { get; set; }
|
||||
internal bool IsValid () { return (WorkbookDoc != null && WorkbookDoc.GetRootElement() != null); }
|
||||
internal bool IsValid() { return (WorkbookDoc != null && WorkbookDoc.GetRootElement() != null); }
|
||||
}
|
||||
private Workbook workbook;
|
||||
private class Worksheet
|
||||
@@ -71,17 +71,17 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
internal SaMsXmlElement ActiveRow { get; set; }
|
||||
}
|
||||
internal NodesData Nodes { get; } = new NodesData();
|
||||
bool IsValid () { return (WorksheetDoc != null && WorksheetDoc.GetRootElement() != null); }
|
||||
bool IsValid() { return (WorksheetDoc != null && WorksheetDoc.GetRootElement() != null); }
|
||||
|
||||
}
|
||||
private Worksheet worksheet;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Construction.
|
||||
public SaMsSpreadsheet_Direct () : base()
|
||||
public SaMsSpreadsheet_Direct() : base()
|
||||
{
|
||||
}
|
||||
protected override void Dispose (bool disposing)
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
@@ -96,11 +96,11 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k b o o k
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorkbookValid ()
|
||||
public override bool IsWorkbookValid()
|
||||
{
|
||||
return (workbook != null && workbook.IsValid());
|
||||
}
|
||||
public override bool CreateWorkbook ()
|
||||
public override bool CreateWorkbook()
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
@@ -113,7 +113,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
|
||||
return SetErrorState("Creating workbook not supported");
|
||||
}
|
||||
public override bool OpenWorkbook (String filePath)
|
||||
public override bool OpenWorkbook(String filePath)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
@@ -138,7 +138,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool OpenWorkbook (byte[] workbookData)
|
||||
public bool OpenWorkbook(byte[] workbookData)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
@@ -152,7 +152,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public bool OpenWorkbook (Stream workbookStream)
|
||||
public bool OpenWorkbook(Stream workbookStream)
|
||||
{
|
||||
CloseWorkbook();
|
||||
ClearErrorState();
|
||||
@@ -172,7 +172,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
private bool ExtractWorkbookElementsFromArchive ()
|
||||
private bool ExtractWorkbookElementsFromArchive()
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -214,19 +214,22 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
catch (Exception exc) { SetErrorState(ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool SaveDocument (String filePath, int fileFormat, bool bAutomaticallyOverwrite)
|
||||
public override bool CleanseWorkbook()
|
||||
{
|
||||
throw new NotSupportedException(SysUtil.Fn);
|
||||
}
|
||||
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");
|
||||
return SetErrorState("Unsupported file format: " + ((XlFileFormat)fileFormat).ToString());
|
||||
if (!IsWorkbookValid()) SetErrorState(Msg_WorkbookNotOpen);
|
||||
SetErrorState("Saving workbook not supported");
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool CloseWorkbook ()
|
||||
public override bool CloseWorkbook()
|
||||
{
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
@@ -247,15 +250,25 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid ()
|
||||
/// <summary>Extract the document as a byte array.</summary>
|
||||
/// <returns>Document data as byte array.</returns>
|
||||
public override byte[] GetDocumentData()
|
||||
{
|
||||
return (worksheet != null && worksheet.WorksheetDoc != null);
|
||||
throw new NotSupportedException(SysUtil.Fn);
|
||||
}
|
||||
|
||||
// Default style.
|
||||
public override void ApplyDefaultStyle(SaMsExcelStyleAttr attr)
|
||||
{
|
||||
throw new NotSupportedException(SysUtil.Fn);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t s
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
public override uint WorksheetCount { get { return workbook.WorksheetCount; } }
|
||||
private void PopulateWorksheetCount ()
|
||||
private void PopulateWorksheetCount()
|
||||
{
|
||||
if (!IsWorkbookValid()) return;
|
||||
try
|
||||
@@ -265,25 +278,32 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
SaMsXmlElement nodeSheets = nodeWorkbook.GetFirstChildElement("sheets");
|
||||
workbook.WorksheetCount = (uint)nodeSheets.GetChildElements("sheet").Count;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetWorksheetCount", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
}
|
||||
public override bool SetWorksheetCount (int worksheetCount)
|
||||
public override bool SetWorksheetCount(int worksheetCount)
|
||||
{
|
||||
ClearErrorState();
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool AddWorksheet(String name)
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override List<String> WorksheetNames
|
||||
{
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool RemoveWorksheet(uint worksheetPos)
|
||||
get
|
||||
{
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
List<String> names = new List<String>();
|
||||
return names;
|
||||
}
|
||||
public override bool OpenWorksheet (uint worksheetPos)
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Open worksheet by position (from 1).
|
||||
/// </summary>
|
||||
public override bool OpenWorksheet(uint worksheetPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (!workbook.IsValid()) return SetErrorState("Workbook is not open");
|
||||
if (!IsWorkbookValid()) return SetErrorState(Msg_WorkbookNotOpen);
|
||||
if (worksheetPos > WorksheetCount) return SetErrorState("Invalid sheet specified");
|
||||
if (worksheetPos <= 0) worksheetPos = Math.Max(1, workbook.ActiveSheetPos);
|
||||
CloseWorksheet();
|
||||
@@ -329,20 +349,70 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
if (worksheet.WorksheetDoc == null) return SetErrorState("Unable to load worksheet " + worksheetPos.ToString());
|
||||
}
|
||||
catch (Exception exc) { HandleException("OpenWorksheet", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override uint WorksheetPos { get { return workbook.ActiveSheetPos; } }
|
||||
public override String WorksheetName
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
/// <summary>
|
||||
/// Open worksheet by position (from 1).
|
||||
/// </summary>
|
||||
public override bool OpenWorksheet(String name)
|
||||
{
|
||||
get { return ""; }
|
||||
set { }
|
||||
}
|
||||
public override bool SetWorksheetAttr (SaMsExcelItemAttr attr)
|
||||
ClearErrorState();
|
||||
if (!IsWorkbookValid()) return SetErrorState(Msg_WorkbookNotOpen);
|
||||
CloseWorksheet();
|
||||
name = StringUtil.TrimWhitespace(name);
|
||||
|
||||
try
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
worksheet = new Worksheet();
|
||||
// Locate worksheet in workbook by 0-index.
|
||||
SaMsXmlElement workbookElement = workbook.WorkbookDoc.GetRootElement();
|
||||
SaMsXmlElement sheetsElement = workbookElement.GetFirstChildElement("sheets");
|
||||
uint worksheetPos = 0;
|
||||
foreach (SaMsXmlElement sheetElement in sheetsElement.GetChildElements("sheet"))
|
||||
{
|
||||
worksheetPos++;
|
||||
String sheetName = sheetElement.GetAttributeValue("name");
|
||||
if (StringUtil.TrimWhitespace(sheetName).EqualsCI(name))
|
||||
{
|
||||
// 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 = sheetName;
|
||||
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;
|
||||
}
|
||||
public override bool CloseWorksheet ()
|
||||
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(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool CloseWorksheet()
|
||||
{
|
||||
ClearErrorState();
|
||||
|
||||
@@ -364,24 +434,51 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet Page Setup.
|
||||
public override bool SetPageSetup (SaMsExcelPageSetup_Config pageSetupConfig)
|
||||
public override bool AddWorksheet(String name)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
public override bool SetPageBreak (uint col, uint row)
|
||||
public override bool RemoveWorksheet(uint worksheetPos)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState("Modifying workbook not supported");
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid()
|
||||
{
|
||||
return (worksheet != null && worksheet.WorksheetDoc != null);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override uint WorksheetPos { get { return workbook.ActiveSheetPos; } }
|
||||
public override String WorksheetName
|
||||
{
|
||||
get { return ""; }
|
||||
set { }
|
||||
}
|
||||
public override bool SetWorksheetAttr(SaMsExcelStyleAttr attr)
|
||||
{
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet Page Setup.
|
||||
public override bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig)
|
||||
{
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
public override bool SetPageBreak(uint col, uint row)
|
||||
{
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveColPos ()
|
||||
{
|
||||
return worksheet.ActiveColPos;
|
||||
}
|
||||
private SaMsXmlElement GetColElement (uint colPos)
|
||||
public override uint ActiveColPos { get { return worksheet.ActiveColPos; } }
|
||||
private SaMsXmlElement GetColElement(uint colPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -399,10 +496,10 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColElement", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override double GetColWidth (uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
public override double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -416,22 +513,35 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(width);
|
||||
return width;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColWidth", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return 0.0;
|
||||
}
|
||||
public override bool SetColWidth (uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
public override bool SetColWidth(uint colPos, double fWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveRowPos ()
|
||||
public override uint FirstRowPos
|
||||
{
|
||||
return worksheet.ActiveRowPos;
|
||||
get
|
||||
{
|
||||
SaMsXmlElement rowElement = worksheet.Nodes.Rows.GetChildElements("row").First();
|
||||
return (uint)(rowElement?.GetAttributeValue("r").ToLong() ?? 0);
|
||||
}
|
||||
SaMsXmlElement GetRowElement (uint rowPos)
|
||||
}
|
||||
public override uint LastRowPos
|
||||
{
|
||||
get
|
||||
{
|
||||
SaMsXmlElement rowElement = worksheet.Nodes.Rows.GetChildElements("row").Last();
|
||||
return (uint)(rowElement?.GetAttributeValue("r").ToLong() ?? 0);
|
||||
}
|
||||
}
|
||||
public override uint ActiveRowPos { get { return worksheet.ActiveRowPos; } }
|
||||
SaMsXmlElement GetRowElement(uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -448,10 +558,10 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowElement", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override double GetRowHeight (uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
public override double GetRowHeight(uint rowPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -465,18 +575,18 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
if (unit == SaExcelLogicalUnit.Inch) return PointsToInches(height);
|
||||
return height;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowHeight", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return 0.0;
|
||||
}
|
||||
public override bool SetRowHeight (uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
public override bool SetRowHeight(uint rowPos, double fHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override List<DataValue> GetRowDataValues (uint rowPos, int maxColumns = 0)
|
||||
public override List<DataValue> GetRowValues(uint rowPos, int maxColumns = 0)
|
||||
{
|
||||
ClearErrorState();
|
||||
List<DataValue> values = new List<DataValue>();
|
||||
@@ -492,17 +602,17 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
if (maxColumns > 0 && values.Count >= maxColumns) break;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowDataValues", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return values;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l s
|
||||
//-------------------------------------------------------------------
|
||||
SaMsXmlElement GetCellElement (uint colPos, uint rowPos)
|
||||
SaMsXmlElement GetCellElement(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
String cellId = GetCellId(colPos,rowPos);
|
||||
String cellId = GetCellId(colPos, rowPos);
|
||||
try
|
||||
{
|
||||
SaMsXmlElement rowElement = GetRowElement(rowPos);
|
||||
@@ -512,88 +622,99 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
return cellElement;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellElement", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
public override void SetActiveCell (uint colPos, uint rowPos)
|
||||
public override void SetActiveCell(uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo SetActiveCell.
|
||||
SetErrorState("Not supported");
|
||||
SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
private bool IsCellFormula (uint colPos, uint rowPos)
|
||||
private bool IsCellFormula(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
bool bIsFormula = false;
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos, rowPos);
|
||||
bIsFormula = !cellElement.GetAttributeValue("f").IsEmpty();
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellFormula", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return bIsFormula;
|
||||
}
|
||||
private bool IsCellNumeric (uint colPos, uint rowPos)
|
||||
private bool IsCellNumeric(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos, rowPos);
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellNumeric(cellElement, cellStyle);
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellNumeric", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return false;
|
||||
}
|
||||
private bool IsCellNumeric (SaMsXmlElement cellElement)
|
||||
private bool IsCellNumeric(SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellNumeric(cellElement, cellStyle);
|
||||
}
|
||||
private bool IsCellNumeric (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
private bool IsCellNumeric(SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
{
|
||||
ClearErrorState();
|
||||
return (cellElement.GetAttributeValue("t").IsEmpty() && !IsDateTimeStyle(cellStyle.NumFmtCode));
|
||||
}
|
||||
private bool IsCellDate (uint colPos, uint rowPos)
|
||||
private bool IsCellDate(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
bool bIsDate = false;
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos, rowPos);
|
||||
SaMsExcelStyle cellStyle = GetCellStyle(cellElement);
|
||||
return IsCellDate(cellElement, cellStyle);
|
||||
}
|
||||
catch (Exception exc) { HandleException("IsCellDate", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return bIsDate;
|
||||
}
|
||||
private bool IsCellDate (SaMsXmlElement cellElement)
|
||||
private bool IsCellDate(SaMsXmlElement cellElement)
|
||||
{
|
||||
return IsCellDate(cellElement, GetCellStyle(cellElement));
|
||||
}
|
||||
private bool IsCellDate (SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
private bool IsCellDate(SaMsXmlElement cellElement, SaMsExcelStyle cellStyle)
|
||||
{
|
||||
ClearErrorState();
|
||||
return IsDateTimeStyle(cellStyle.NumFmtCode);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public override String GetCellFormula (uint colPos, uint rowPos)
|
||||
public override String GetCellFormula(uint colPos, uint rowPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos,rowPos);
|
||||
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); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return "";
|
||||
}
|
||||
private String GetCellText (SaMsXmlElement cellElement, bool trimValue = true)
|
||||
public override String GetCellText(uint colPos, uint rowPos, bool trimWhitespace = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
SaMsXmlElement cellElement = GetCellElement(colPos, rowPos);
|
||||
return GetCellText(cellElement, true);
|
||||
}
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return "";
|
||||
}
|
||||
private String GetCellText(SaMsXmlElement cellElement, bool trimValue = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
String value = "";
|
||||
@@ -605,14 +726,14 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
value = cellElement.GetChildText("v");
|
||||
if (trimValue) value.TrimAll();
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellText", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return value;
|
||||
}
|
||||
public override DataValue GetCellDataValue (uint colPos, uint rowPos)
|
||||
public override DataValue GetCellValue(uint colPos, uint rowPos)
|
||||
{
|
||||
return GetCellDataValue(GetCellElement(colPos, rowPos), false);
|
||||
}
|
||||
private DataValue GetCellDataValue (SaMsXmlElement cellElement, bool trimTextValue = true)
|
||||
private DataValue GetCellDataValue(SaMsXmlElement cellElement, bool trimTextValue = true)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -645,12 +766,12 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
return new DataValue(value);
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetCellDataValue", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return new DataValue();
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
// Shared string for cell.
|
||||
private String GetSharedString (SaMsXmlElement nodeElement)
|
||||
private String GetSharedString(SaMsXmlElement nodeElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
@@ -658,10 +779,10 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
SaMsXmlElement sharedStringElement = GetSharedStringElement(nodeElement);
|
||||
return sharedStringElement.GetChildText("t");
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetSharedString", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return "";
|
||||
}
|
||||
private SaMsXmlElement GetSharedStringElement (SaMsXmlElement cellElement)
|
||||
private SaMsXmlElement GetSharedStringElement(SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
if (workbook.SharedStringsDoc == null || cellElement == null || !cellElement.Valid) return null;
|
||||
@@ -678,31 +799,23 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
return siElement;
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetSharedStringNode", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return new SaMsXmlElement(null);
|
||||
}
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SetCellFormula (uint colPos, uint rowPos, String value)
|
||||
public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
public override bool SetCellFormula (uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr)
|
||||
public override bool SetCellValue(uint colPos, uint rowPos, DataValue value, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetRowFormulas (uint colPosStart, uint rowPos, List<Object> values)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
}
|
||||
public override bool SetRangeFormulas (SaMsExcelRange range, List<Object> values)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// C e l l S t y l e
|
||||
//-------------------------------------------------------------------
|
||||
private String GetBuiltInStyleFormat (int numFmtId)
|
||||
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)
|
||||
@@ -758,7 +871,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
return "";
|
||||
}
|
||||
private SaMsExcelStyle GetCellStyle (SaMsXmlElement cellElement)
|
||||
private SaMsExcelStyle GetCellStyle(SaMsXmlElement cellElement)
|
||||
{
|
||||
ClearErrorState();
|
||||
SaMsExcelStyle style = new SaMsExcelStyle();
|
||||
@@ -845,10 +958,10 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetStyleNode", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return style;
|
||||
}
|
||||
private bool IsDateStyle (String numFormat)
|
||||
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;
|
||||
@@ -857,7 +970,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
if (numFormat.Contains("y")) return true;
|
||||
return false;
|
||||
}
|
||||
private bool IsTimeStyle (String numFormat)
|
||||
private bool IsTimeStyle(String numFormat)
|
||||
{
|
||||
if (numFormat.Contains("h")) return true;
|
||||
if (numFormat.Contains(":mm")) return true;
|
||||
@@ -865,41 +978,41 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
if (numFormat.Contains(":ss")) return true;
|
||||
return false;
|
||||
}
|
||||
private bool IsDateTimeStyle (String numFormat)
|
||||
private bool IsDateTimeStyle(String numFormat)
|
||||
{
|
||||
return (IsDateStyle(numFormat) || IsTimeStyle(numFormat));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public override bool SetRangeAttr (SaMsExcelRange range, SaMsExcelItemAttr attr)
|
||||
public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Add image to sheet.
|
||||
public override bool InsertImage (SaMsExcelImage_Config imageConfig)
|
||||
public override bool InsertImage(SaMsExcelImage_Config imageConfig)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool FreezePanes (uint colPos, uint rowPos)
|
||||
public override bool FreezePanes(uint colPos, uint rowPos)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool AutoFit (SaMsExcelRange range)
|
||||
public override bool AutoFitRows(SaMsExcelRange range)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SelectRange (SaMsExcelRange range)
|
||||
public override bool SelectRange(SaMsExcelRange range)
|
||||
{
|
||||
return SetErrorState("Not supported");
|
||||
return SetErrorState(SysUtil.Fn + " " + Msg_NotSupported);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
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;
|
||||
using DocumentFormat.OpenXml.Packaging;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using Sarand.Net.Standard.Base.App;
|
||||
using Sarand.Net.Standard.Base.Core;
|
||||
using Sarand.Net.Standard.Base.Utils;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
@@ -118,6 +116,10 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
catch (Exception exc) { SaLogger.Warn(exc.GetType().Name + ".OpenWorkbook " + ExceptionUtil.GetErrorStateMessage(exc)); }
|
||||
return (workbook != null);
|
||||
}
|
||||
public override bool CleanseWorkbook()
|
||||
{
|
||||
throw new NotSupportedException(SysUtil.Fn);
|
||||
}
|
||||
public override bool SaveDocument(String filePath, int fileFormat, bool bAutomaticallyOverwrite)
|
||||
{
|
||||
ClearErrorState();
|
||||
@@ -156,13 +158,22 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid()
|
||||
/// <summary>Extract the document as a byte array.</summary>
|
||||
/// <returns>Document data as byte array.</returns>
|
||||
public override byte[] GetDocumentData()
|
||||
{
|
||||
return (worksheet != null);
|
||||
throw new NotSupportedException(SysUtil.Fn);
|
||||
}
|
||||
|
||||
// Default style.
|
||||
public override void ApplyDefaultStyle(SaMsExcelStyleAttr attr)
|
||||
{
|
||||
throw new NotSupportedException(SysUtil.Fn);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint WorksheetCount
|
||||
{
|
||||
get
|
||||
@@ -187,6 +198,11 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
else SetErrorState("SetWorksheetCount - Requested number of worksheets (" + worksheetCount.ToString() + ") must be between 1 and 10");
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override List<String> WorksheetNames { get { return new List<String>(); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool AddWorksheet(String sheetName)
|
||||
{
|
||||
ClearErrorState();
|
||||
@@ -214,6 +230,8 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
|
||||
return (worksheet != null);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool RemoveWorksheet(uint worksheetPos)
|
||||
{
|
||||
ClearErrorState();
|
||||
@@ -243,9 +261,12 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// W o r k s h e e t
|
||||
//-------------------------------------------------------------------
|
||||
public override bool OpenWorksheet(uint worksheetPos)
|
||||
{
|
||||
String fn = GetType().Name + ".OpenWorksheet";
|
||||
ClearErrorState();
|
||||
CloseWorksheet();
|
||||
|
||||
@@ -267,31 +288,49 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
if (worksheetPart != null && sheet != null)
|
||||
worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet);
|
||||
}
|
||||
|
||||
if (worksheet != null)
|
||||
{
|
||||
SaLogger.Warn(fn + " Failed to open worksheet " + worksheetPos);
|
||||
SaLogger.Warn(SysUtil.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)
|
||||
|
||||
public override bool OpenWorksheet(String name)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
CloseWorksheet();
|
||||
name = StringUtil.TrimWhitespace(name);
|
||||
|
||||
// Extract Sheet by position.
|
||||
uint worksheetPos = 0;
|
||||
Sheet sheet = null;
|
||||
foreach (Sheet sheetCandidate in Sheets)
|
||||
{
|
||||
// ToDo OpenXml SetWorksheetAttr
|
||||
++worksheetPos;
|
||||
if (StringUtil.TrimWhitespace(sheetCandidate.Name).EqualsCI(name))
|
||||
{
|
||||
sheet = sheetCandidate;
|
||||
break;
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetWorksheetAttr", exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
if (sheet != null)
|
||||
{
|
||||
WorksheetPart worksheetPart = (WorksheetPart)(WorkbookPart.GetPartById(sheet.Id));
|
||||
|
||||
if (worksheetPart != null && sheet != null)
|
||||
worksheet = new WorksheetData(worksheetPos, worksheetPart, sheet);
|
||||
}
|
||||
if (worksheet != null)
|
||||
{
|
||||
String msg = "Failed to open worksheet: " + name;
|
||||
SetErrorState(msg);
|
||||
SaLogger.Warn(SysUtil.Fn + " " + msg);
|
||||
}
|
||||
return (worksheet != null);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool CloseWorksheet()
|
||||
{
|
||||
ClearErrorState();
|
||||
@@ -303,12 +342,38 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
worksheet = null;
|
||||
}
|
||||
catch (Exception exc) { HandleException("CloseWorksheet", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
worksheet = null;
|
||||
activeWorksheetPos = 0;
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool IsWorksheetValid()
|
||||
{
|
||||
return (worksheet != null);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override uint WorksheetPos { get { return activeWorksheetPos; } }
|
||||
public override String WorksheetName
|
||||
{
|
||||
get { return worksheet.Sheet.Name; }
|
||||
set { worksheet.Sheet.Name = StringUtil.Left(value, 31); }
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SetWorksheetAttr(SaMsExcelStyleAttr attr)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXml SetWorksheetAttr
|
||||
}
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Worksheet Page Setup.
|
||||
public override bool SetPageSetup(SaMsExcelPageSetup_Config pageSetupConfig)
|
||||
@@ -428,7 +493,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
*/
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetPageSetup", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
public override bool SetPageBreak(uint colPos, uint rowPos)
|
||||
@@ -445,7 +510,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
worksheet.VPageBreaks.Add(range);
|
||||
*/
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetPageSetup", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
@@ -459,7 +524,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
//-------------------------------------------------------------------
|
||||
// C o l u m n s
|
||||
//-------------------------------------------------------------------
|
||||
private Column GetColumnByPos (uint columnPos)
|
||||
private Column GetColumnByPos(uint columnPos)
|
||||
{
|
||||
if (worksheet.ActiveColumnPos != columnPos)
|
||||
{
|
||||
@@ -468,16 +533,19 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
}
|
||||
return worksheet.ActiveColumn;
|
||||
}
|
||||
public override uint GetActiveColPos()
|
||||
public override uint ActiveColPos
|
||||
{
|
||||
get
|
||||
{
|
||||
if (worksheet == null) return 0;
|
||||
try
|
||||
{
|
||||
return worksheet.ActiveColumnPos;
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetActiveCol", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
public override double GetColWidth(uint colPos, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
{
|
||||
double columnWidth = 0.0;
|
||||
@@ -485,7 +553,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML GetColWidth.
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetColWidth", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return columnWidth;
|
||||
}
|
||||
public override bool SetColWidth(uint colPos, double columnWidth, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
@@ -495,23 +563,30 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML SetColWidth.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetColWidth", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// R o w s
|
||||
//-------------------------------------------------------------------
|
||||
public override uint GetActiveRowPos()
|
||||
public override uint FirstRowPos { get { return (uint)(0); } }
|
||||
public override uint LastRowPos { get { return (uint)(0); } }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override uint ActiveRowPos
|
||||
{
|
||||
get
|
||||
{
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML GetActiveRowPos.
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetActiveRowPos", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return 0;
|
||||
}
|
||||
public override List<DataValue> GetRowDataValues(uint rowPos, int maxColumns = 0)
|
||||
}
|
||||
public override List<DataValue> GetRowValues(uint rowPos, int maxColumns = 0)
|
||||
{
|
||||
List<DataValue> values = new List<DataValue>();
|
||||
return values;
|
||||
@@ -523,7 +598,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML GetRowHeight.
|
||||
}
|
||||
catch (Exception exc) { HandleException("GetRowHeight", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return rowHeight;
|
||||
}
|
||||
public override bool SetRowHeight(uint rowPos, double rowHeight, SaExcelLogicalUnit unit = SaExcelLogicalUnit.Point)
|
||||
@@ -533,7 +608,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML SetRowHeight.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetRowHeight", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
@@ -549,52 +624,50 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
// ToDo OpenXML GetCellFormula.
|
||||
return "";
|
||||
}
|
||||
public override DataValue GetCellDataValue(uint colPos, uint rowPos)
|
||||
public override String GetCellText(uint colPos, uint rowPos, bool trimWhitespace = true)
|
||||
{
|
||||
// ToDo OpenXML GetCellText.
|
||||
return "";
|
||||
}
|
||||
public override DataValue GetCellValue(uint colPos, uint rowPos)
|
||||
{
|
||||
// ToDo OpenXML GetCellDataValue.
|
||||
return new DataValue();
|
||||
}
|
||||
public override bool SetCellFormula(uint colPos, uint rowPos, String value)
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
// ToDo OpenXML SetCellFormula.
|
||||
return true;
|
||||
}
|
||||
public override bool SetCellFormula(uint colPos, uint rowPos, String value, SaMsExcelItemAttr attr)
|
||||
|
||||
public override bool SetCellValue(uint colPos, uint rowPos, DataValue value, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
// ToDo OpenXML SetCellFormula.
|
||||
return true;
|
||||
}
|
||||
public override bool SetRowFormulas(uint colPosStart, uint rowPos, List<Object> values)
|
||||
{
|
||||
// ToDo OpenXML SetRowFormulas.
|
||||
return true;
|
||||
}
|
||||
public override bool SetRangeFormulas(SaMsExcelRange range, List<Object> values)
|
||||
{
|
||||
// ToDo OpenXML SetRangeFormulas.
|
||||
// ToDo OpenXML SetCellValue.
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Cell attributes.
|
||||
public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelItemAttr attr)
|
||||
public override bool SetRangeAttr(SaMsExcelRange range, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SetRangeAttr.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetRangeAttr", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
private bool SetRangeAttr(Range oRange, SaMsExcelItemAttr attr)
|
||||
private bool SetRangeAttr(Range oRange, SaMsExcelStyleAttr attr)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML SetRangeAttr.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SetRangeAttr", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
@@ -610,7 +683,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML InsertImage.
|
||||
}
|
||||
catch (Exception exc) { HandleException("InsertImage", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
@@ -622,19 +695,19 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML FreezePanes.
|
||||
}
|
||||
catch (Exception exc) { HandleException("FreezePanes", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
public override bool AutoFit(SaMsExcelRange range)
|
||||
public override bool AutoFitRows(SaMsExcelRange range)
|
||||
{
|
||||
ClearErrorState();
|
||||
try
|
||||
{
|
||||
// ToDo OpenXML AutoFit.
|
||||
}
|
||||
catch (Exception exc) { HandleException("AutoFit", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
@@ -646,7 +719,7 @@ namespace Sarand.Net.Standard.Proc.Excel
|
||||
{
|
||||
// ToDo OpenXML SelectRange.
|
||||
}
|
||||
catch (Exception exc) { HandleException("SelectRange", exc); }
|
||||
catch (Exception exc) { HandleException(SysUtil.Fn, exc); }
|
||||
return !HasErrorState();
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -43,22 +43,6 @@ namespace Sarand.Net.Standard.Proc.Procs
|
||||
// Utilities.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Run asynchronous.
|
||||
//-------------------------------------------------------------------
|
||||
public bool RunAsync()
|
||||
{
|
||||
// Run on separate thread.
|
||||
Thread thread = new Thread(new ThreadStart(RunOnThread));
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
return true;
|
||||
}
|
||||
private void RunOnThread()
|
||||
{
|
||||
RunProcess();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
}
|
||||
//=======================================================================
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netstandard2.1</TargetFramework>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<RootNamespace>Sarand.Net.Standard</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="DocumentFormat.OpenXml" Version="2.12.3" />
|
||||
<PackageReference Include="NPOI" Version="2.5.3" />
|
||||
<PackageReference Include="NPOI" Version="2.6.2" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user