diff --git a/Demos/Reports/Polygon.frx b/Demos/Reports/Polygon.frx index 85e2cab6..8a61e17f 100644 --- a/Demos/Reports/Polygon.frx +++ b/Demos/Reports/Polygon.frx @@ -1,26 +1,29 @@  - + - + - + - - - - - - - - - + + + + + + + + + + + + - + diff --git a/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/FastReport.OpenSource.Export.PdfSimple.Tests.csproj b/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/FastReport.OpenSource.Export.PdfSimple.Tests.csproj index ae3dbb80..95bfe599 100644 --- a/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/FastReport.OpenSource.Export.PdfSimple.Tests.csproj +++ b/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/FastReport.OpenSource.Export.PdfSimple.Tests.csproj @@ -20,6 +20,9 @@ PreserveNewest + + PreserveNewest + diff --git a/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/PdfSimpleExportTests.cs b/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/PdfSimpleExportTests.cs index 5db628a9..78a40471 100644 --- a/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/PdfSimpleExportTests.cs +++ b/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/PdfSimpleExportTests.cs @@ -80,6 +80,16 @@ public void TestExportPdfInfo() #pragma warning restore xUnit2009 // Do not use boolean check to check for substrings } + [Fact] + public void TestExportWatermark() + { + Report r = new Report(); + r.LoadPrepared("Watermark.fpx"); + + PDFSimpleExport export = new PDFSimpleExport(); + r.Export(export, "Watermark.pdf"); + } + [Fact] public void TestExportPdfImages() { diff --git a/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/Watermark.fpx b/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/Watermark.fpx new file mode 100644 index 00000000..8858366a Binary files /dev/null and b/Extras/OpenSource/FastReport.OpenSource.Export.PdfSimple/FastReport.OpenSource.Export.PdfSimple.Tests/Watermark.fpx differ diff --git a/FastReport.Base/AssemblyInitializer.cs b/FastReport.Base/AssemblyInitializer.cs index b0f472fc..22a13646 100644 --- a/FastReport.Base/AssemblyInitializer.cs +++ b/FastReport.Base/AssemblyInitializer.cs @@ -45,6 +45,12 @@ public AssemblyInitializer() RegisteredObjects.AddConnection(typeof(XmlDataConnection)); RegisteredObjects.AddConnection(typeof(CsvDataConnection)); + // json + RegisteredObjects.Add(typeof(Data.JsonConnection.JsonTableDataSource), "", 0); + //RegisteredObjects.Add(typeof(Data.JsonConnection.JsonObjectDataSource), "", 0); + //RegisteredObjects.Add(typeof(Data.JsonConnection.JsonArrayDataSource), "", 0); + RegisteredObjects.AddConnection(typeof(Data.JsonConnection.JsonDataSourceConnection)); + // formats RegisteredObjects.Add(typeof(BooleanFormat), "", 0); RegisteredObjects.Add(typeof(CurrencyFormat), "", 0); diff --git a/FastReport.Base/BandBase.cs b/FastReport.Base/BandBase.cs index 809ad99c..75e888f1 100644 --- a/FastReport.Base/BandBase.cs +++ b/FastReport.Base/BandBase.cs @@ -37,6 +37,7 @@ public abstract partial class BandBase : BreakableComponent, IParent private float reprintOffset; private string beforeLayoutEvent; private string afterLayoutEvent; + private int repeatBandNTimes = 1; #endregion @@ -67,6 +68,17 @@ public bool StartNewPage set { startNewPage = value; } } + /// + /// Gets or sets a value that determines the number of repetitions of the same band. + /// + [Category("Behavior")] + [DefaultValue(1)] + public int RepeatBandNTimes + { + get { return repeatBandNTimes; } + set { repeatBandNTimes = value; } + } + /// /// Gets or sets a value indicating that the first row can start a new report page. /// @@ -512,6 +524,7 @@ public override void Assign(Base source) OutlineExpression = src.OutlineExpression; BeforeLayoutEvent = src.BeforeLayoutEvent; AfterLayoutEvent = src.AfterLayoutEvent; + RepeatBandNTimes = src.RepeatBandNTimes; } internal virtual void UpdateWidth() @@ -631,6 +644,8 @@ public override void Serialize(FRWriter writer) writer.WriteStr("BeforeLayoutEvent", BeforeLayoutEvent); if (AfterLayoutEvent != c.AfterLayoutEvent) writer.WriteStr("AfterLayoutEvent", AfterLayoutEvent); + if (RepeatBandNTimes != c.RepeatBandNTimes) + writer.WriteInt("RepeatBandNTimes", RepeatBandNTimes); } internal bool IsColumnDependentBand diff --git a/FastReport.Base/Code/AssemblyDescriptor.cs b/FastReport.Base/Code/AssemblyDescriptor.cs index 77249426..7e755b5f 100644 --- a/FastReport.Base/Code/AssemblyDescriptor.cs +++ b/FastReport.Base/Code/AssemblyDescriptor.cs @@ -181,7 +181,7 @@ private void AddReferencedAssemblies(StringCollection assemblies, string default foreach (string s in Report.ReferencedAssemblies) { //TODO thid core directive only for .net standard mode replace with checking the standard -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 if (s == "System.Windows.Forms.dll") continue; diff --git a/FastReport.Base/Data/DataConnectionBase.cs b/FastReport.Base/Data/DataConnectionBase.cs index 0a5f6f3d..97be1626 100644 --- a/FastReport.Base/Data/DataConnectionBase.cs +++ b/FastReport.Base/Data/DataConnectionBase.cs @@ -328,7 +328,7 @@ public void CreateAllTables() /// Fills the collection with all tables available in the database. /// /// Set to true to initialize each table's schema. - public void CreateAllTables(bool initSchema) + public virtual void CreateAllTables(bool initSchema) { List tableNames = new List(); tableNames.AddRange(GetTableNames()); @@ -404,7 +404,7 @@ public void CreateAllTables(bool initSchema) /// /// Creates the relations between tables. Applies to XmlDataConnection only. /// - public void CreateRelations() + public virtual void CreateRelations() { if (Report != null) { diff --git a/FastReport.Base/Data/DataSourceBase.cs b/FastReport.Base/Data/DataSourceBase.cs index 7c073695..face4648 100644 --- a/FastReport.Base/Data/DataSourceBase.cs +++ b/FastReport.Base/Data/DataSourceBase.cs @@ -19,7 +19,7 @@ public abstract class DataSourceBase : Column private ArrayList internalRows; private ArrayList rows; private int currentRowNo; - private object currentRow; + protected object currentRow; private Hashtable additionalFilter; private bool forceLoadData; private Hashtable columnIndices; diff --git a/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs new file mode 100644 index 00000000..b2343ccc --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs @@ -0,0 +1,259 @@ +using FastReport.Data.JsonConnection.JsonParser; +using System; +using System.Data; +using System.Data.Common; +using System.Net; +using System.Text; + +namespace FastReport.Data.JsonConnection +{ + /// + /// FastReport json connection + /// + public partial class JsonDataSourceConnection : DataConnectionBase + { + #region Public Fields + + /// + /// Name of json object table + /// + public const string TABLE_NAME = "JSON"; + + #endregion Public Fields + + #region Private Fields + + private JsonArray jsonInternal = null; + private JsonSchema jsonSchema = null; + private string jsonSchemaString = ""; + + #endregion Private Fields + + #region Internal Properties + + internal JsonArray Json + { + get + { + if (jsonInternal == null) + InitConnection(); + return jsonInternal; + } + } + + internal JsonSchema JsonSchema + { + get + { + if (jsonSchema == null) + InitConnection(); + return jsonSchema; + } + } + + #endregion Internal Properties + + #region Public Constructors + + /// + /// Initialize a new instance + /// + public JsonDataSourceConnection() + { + IsSqlBased = false; + } + + #endregion Public Constructors + + #region Public Methods + + /// + public override void CreateAllTables(bool initSchema) + { + bool found = false; + foreach (Base b in Tables) + { + if (b is JsonTableDataSource) + { + (b as JsonTableDataSource).UpdateSchema = true; + (b as JsonTableDataSource).InitSchema(); + found = true; + break; + } + } + + if (!found) + { + JsonTableDataSource jsonDataSource = new JsonTableDataSource(); + + string fixedTableName = TABLE_NAME; + jsonDataSource.TableName = fixedTableName; + + if (Report != null) + { + jsonDataSource.Name = Report.Dictionary.CreateUniqueName(fixedTableName); + jsonDataSource.Alias = Report.Dictionary.CreateUniqueAlias(jsonDataSource.Alias); + } + else + jsonDataSource.Name = fixedTableName; + + jsonDataSource.Parent = this; + jsonDataSource.InitSchema(); + jsonDataSource.Enabled = true; + } + + // init table schema + if (initSchema) + { + foreach (TableDataSource table in Tables) + { + table.InitSchema(); + } + } + } + + /// + public override void CreateRelations() + { + } + + /// + public override void CreateTable(TableDataSource source) + { + //throw new NotImplementedException(); + } + + /// + public override void DeleteTable(TableDataSource source) + { + //throw new NotImplementedException(); + } + + /// + public override void FillTableData(DataTable table, string selectCommand, CommandParameterCollection parameters) + { + } + + /// + public override void FillTableSchema(DataTable table, string selectCommand, CommandParameterCollection parameters) + { + } + + /// + public override string[] GetTableNames() + { + return new string[] { TABLE_NAME }; + } + + /// + public override string QuoteIdentifier(string value, DbConnection connection) + { + return value; + } + + #endregion Public Methods + + #region Protected Methods + + /// + protected override DataSet CreateDataSet() + { + throw new NotImplementedException(); + } + + /// + protected override void SetConnectionString(string value) + { + jsonInternal = null; + base.SetConnectionString(value); + } + + #endregion Protected Methods + + #region Private Methods + + private void InitConnection() + { + InitConnection(false); + } + + private void InitConnection(bool rebuildSchema) + { + JsonDataSourceConnectionStringBuilder builder = new JsonDataSourceConnectionStringBuilder(ConnectionString); + JsonBase obj = null; + string jsonText = builder.Json.Trim(); + if(jsonText.Length >0) + { + if(!(jsonText[0] == '{' || jsonText[0] == '[')) + { + using (WebClient client = new WebClient()) + { + try + { + client.Encoding = Encoding.GetEncoding(builder.Encoding); + } + catch + { + client.Encoding = Encoding.UTF8; + } + jsonText = client.DownloadString(jsonText); + } + } + obj = JsonBase.FromString(jsonText) as JsonBase; + } + + string schema = builder.JsonSchema; + + // have to update schema + if (schema != jsonSchemaString || jsonSchema == null || String.IsNullOrEmpty(jsonSchemaString)) + { + JsonSchema schemaObj = null; + if (String.IsNullOrEmpty(schema) || rebuildSchema) + { + if (obj != null) + { + schemaObj = JsonSchema.FromJson(obj); + JsonObject child = new JsonObject(); + schemaObj.Save(child); + jsonSchemaString = child.ToString(); + } + } + else + { + schemaObj = JsonSchema.Load(JsonBase.FromString(schema) as JsonObject); + jsonSchemaString = schema; + } + + if (schemaObj == null) + { + schemaObj = new JsonSchema(); + schemaObj.Type = "array"; + } + + if (schemaObj.Type != "array") + { + JsonSchema parentSchema = new JsonSchema(); + parentSchema.Items = schemaObj; + parentSchema.Type = "array"; + schemaObj = parentSchema; + } + + jsonSchema = schemaObj; + } + + if (obj is JsonArray) + { + jsonInternal = obj as JsonArray; + } + else + { + JsonArray result = new JsonArray(); + if (obj != null) + result.Add(obj); + jsonInternal = result; + } + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs new file mode 100644 index 00000000..08c2018d --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs @@ -0,0 +1,96 @@ +using System.Data.Common; + +namespace FastReport.Data.JsonConnection +{ + /// + /// Represents the JsonDataConnection connection string builder. + /// + /// + /// Use this class to parse connection string returned by the JsonDataConnection class. + /// + public class JsonDataSourceConnectionStringBuilder : DbConnectionStringBuilder + { + #region Public Properties + + /// + /// Gets or sets json data + /// + public string Json + { + get + { + object result; + if (TryGetValue("Json", out result) && result != null) + return (string)result; + return ""; + } + set + { + base["Json"] = value; + } + } + + /// + /// Gets or sets json schema + /// + public string JsonSchema + { + get + { + object result; + if (TryGetValue("JsonSchema", out result) && result != null) + return (string)result; + return ""; + } + set + { + base["JsonSchema"] = value; + } + } + + /// + /// Gets or sets json url encoding + /// + public string Encoding + { + get + { + object result; + if (TryGetValue("Encoding", out result) && result != null) + return (string)result; + return ""; + } + set + { + base["Encoding"] = value; + } + } + + + + #endregion Public Properties + + #region Public Constructors + + /// + /// Initializes a new instance of the class with default settings. + /// + public JsonDataSourceConnectionStringBuilder() + { + ConnectionString = ""; + } + + /// + /// Initializes a new instance of the class with + /// specified connection string. + /// + /// The connection string. + public JsonDataSourceConnectionStringBuilder(string connectionString) + : base() + { + ConnectionString = connectionString; + } + + #endregion Public Constructors + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonParser/JsonArray.cs b/FastReport.Base/Data/JsonConnection/JsonParser/JsonArray.cs new file mode 100644 index 00000000..e1236d87 --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonParser/JsonArray.cs @@ -0,0 +1,110 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace FastReport.Data.JsonConnection.JsonParser +{ + internal class JsonArray : JsonBase, IEnumerable + { + #region Private Fields + + private List array = new List(); + + #endregion Private Fields + + #region Public Indexers + + public override object this[int index] + { + get + { + if (index >= 0 && index < Count) + return array[index]; + return null; + } + + set + { + array[index] = value; + } + } + + #endregion Public Indexers + + #region Public Properties + + public override int Count + { + get + { + return array.Count; + } + } + + public override bool IsArray + { + get + { + return true; + } + } + + #endregion Public Properties + + #region Public Methods + + public void Add(object obj) + { + array.Add(obj); + } + + public IEnumerator GetEnumerator() + { + return array.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return array.GetEnumerator(); + } + + public void Insert(int index, object obj) + { + array.Insert(index, obj); + } + + public void Remove(int index) + { + array.RemoveAt(index); + } + + public override void WriteTo(StringBuilder sb, int indent) + { + sb.Append("["); + + bool notFirst = false; + foreach (object item in array) + { + if (notFirst) + sb.Append(","); + if (indent > 0) + { + sb.AppendLine(); + for (int i = 0; i < indent; i++) + sb.Append(' '); + } + WriteValue(sb, item, indent); + notFirst = true; + } + if (indent > 0 && notFirst) + { + sb.AppendLine(); + for (int i = 2; i < indent; i++) + sb.Append(' '); + } + sb.Append("]"); + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonParser/JsonBase.cs b/FastReport.Base/Data/JsonConnection/JsonParser/JsonBase.cs new file mode 100644 index 00000000..ea0010d3 --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonParser/JsonBase.cs @@ -0,0 +1,576 @@ +using FastReport.Data.JsonConnection.JsonParser; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Text; + +namespace FastReport +{ + /// + /// Allows working with JsonObject + /// + public abstract class JsonBase + { + #region Private Fields + + private static NumberFormatInfo format; + + #endregion Private Fields + + #region Public Indexers + + /// + /// Returns child object for JsonArray + /// + /// + /// + public virtual object this[int index] + { + get + { + return null; + } + set + { + } + } + + /// + /// Returns child object for JsonObject + /// + /// + /// + public virtual object this[string key] + { + get + { + return null; + } + set + { + } + } + + #endregion Public Indexers + + #region Public Properties + + /// + /// Returns count of child object + /// + public virtual int Count + { + get + { + return 0; + } + } + + /// + /// Returns true if this object is JsonArray + /// + public virtual bool IsArray + { + get + { + return false; + } + } + + /// + /// Returns true if this object is JsonObject + /// + public virtual bool IsObject + { + get + { + return false; + } + } + + /// + /// Returns list of JsonObject keys + /// + public virtual IEnumerable Keys + { + get + { + yield break; + } + } + + #endregion Public Properties + + #region Public Constructors + + static JsonBase() + { + format = new NumberFormatInfo(); + format.NumberGroupSeparator = String.Empty; + format.NumberDecimalSeparator = "."; + } + + #endregion Public Constructors + + #region Public Methods + + /// + /// Pars json text string and return a new JsonBase Object + /// + /// + /// + public static JsonBase FromString(string jsonText) + { + using (JsonTextReader reader = new JsonTextReader(jsonText)) + { + return FromTextReader(reader); + } + } + + /// + /// returns true + /// + /// + /// + public virtual bool ContainsKey(string key) + { + return false; + } + + public override string ToString() + { + StringBuilder sb = new StringBuilder(); + WriteTo(sb, 0); + return sb.ToString(); + } + + /// + /// Serialize this object to sb + /// + /// + /// + /// indent in space, 0 = without indent + public abstract void WriteTo(StringBuilder sb, int indent); + + #endregion Public Methods + + #region Internal Methods + + internal string ReadString(string key) + { + object result = this[key]; + if (result != null) + { + return result.ToString(); + } + return null; + } + + internal void WriteValue(StringBuilder sb, object item, int indent) + { + if (item is JsonBase) + { + if (indent > 0) + { + (item as JsonBase).WriteTo(sb, indent + 2); + } + else + { + (item as JsonBase).WriteTo(sb, 0); + } + } + else if (item is bool) + { + if (item.Equals(true)) + { + sb.Append("true"); + } + else + { + sb.Append("false"); + } + } + else if (IsNumber(sb, item)) + { + sb.Append(((IConvertible)item).ToString(format)); + } + else if (item == null) + { + sb.Append("null"); + } + else + { + sb.Append('"'); + + foreach (char c in item.ToString()) + { + switch (c) + { + case '"': sb.Append("\\\""); break; + case '\\': sb.Append("\\\\"); break; + case '/': sb.Append("\\/"); break; + case '\b': sb.Append("\\b"); break; + case '\f': sb.Append("\\f"); break; + case '\n': sb.Append("\\n"); break; + case '\r': sb.Append("\\r"); break; + case '\t': sb.Append("\\t"); break; + default: sb.Append(c); break; + } + } + sb.Append('"'); + } + } + + #endregion Internal Methods + + #region Private Methods + + private static JsonBase FromTextReader(JsonTextReader reader) + { + reader.SkipWhiteSpace(); + if (reader.IsNotEOF) + switch (reader.Char) + { + case '{': + return ReadObject(reader); + + case '[': + return ReadArray(reader); + + default: + throw reader.ThrowFormat('{', '['); + } + throw reader.ThrowEOF('{', '['); + } + + private static JsonArray ReadArray(JsonTextReader reader) + { + if (reader.Char != '[') + throw reader.ThrowFormat('['); + + JsonArray result = new JsonArray(); + + reader.ReadNext(); + reader.SkipWhiteSpace(); + + if (reader.IsEOF) + throw reader.ThrowEOF(']'); + else if (reader.Char != ']') + { + while (true) + { + result.Add(ReadValue(reader)); + reader.SkipWhiteSpace(); + + if (reader.IsEOF) + throw reader.ThrowEOF(']'); + else if (reader.Char == ',') + { + reader.ReadNext(); + reader.SkipWhiteSpace(); + continue; + } + else if (reader.Char == ']') + break; + else reader.ThrowFormat(',', ']'); + } + } + + reader.ReadNext(); + + return result; + } + + private static JsonObject ReadObject(JsonTextReader reader) + { + if (reader.Char != '{') + throw reader.ThrowFormat('{'); + + JsonObject result = new JsonObject(); + + reader.ReadNext(); + reader.SkipWhiteSpace(); + + if (reader.IsEOF) + throw reader.ThrowEOF('}'); + else if (reader.Char != '}') + { + while (true) + { + string key = reader.Dedublicate(ReadValueString(reader)); + + reader.SkipWhiteSpace(); + + if (reader.IsEOF) + throw reader.ThrowEOF(':'); + else if (reader.Char != ':') + reader.ThrowFormat(':'); + + reader.ReadNext(); + reader.SkipWhiteSpace(); + + result[key] = ReadValue(reader); + reader.SkipWhiteSpace(); + + if (reader.IsEOF) + throw reader.ThrowEOF('}'); + else if (reader.Char == ',') + { + reader.ReadNext(); + reader.SkipWhiteSpace(); + continue; + } + else if (reader.Char == '}') + break; + else reader.ThrowFormat(',', '}'); + } + } + + reader.ReadNext(); + + return result; + } + + private static object ReadValue(JsonTextReader reader) + { + if (reader.IsEOF) + throw reader.ThrowEOF('"', '[', '{', 'n', 't', 'f', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + switch (reader.Char) + { + case '"': + return ReadValueString(reader); + + case '[': + return ReadArray(reader); + + case '{': + return ReadObject(reader); + + case 'n': + return ReadValue(reader, "null", null); + + case 't': + return ReadValue(reader, "true", true); + + case 'f': + return ReadValue(reader, "false", false); + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return ReadValueNumber(reader); + + default: + throw reader.ThrowFormat('"', '[', '{', 'n', 't', 'f', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + } + } + + private static object ReadValue(JsonTextReader reader, string str, object result) + { + for (int i = 0; i < str.Length; i++) + { + if (reader.IsEOF) + throw reader.ThrowEOF(str[i]); + else if (reader.Char != str[i]) + throw reader.ThrowFormat(str[i]); + reader.ReadNext(); + } + return result; + } + + private static double ReadValueNumber(JsonTextReader reader) + { + int startPos = reader.Position; + if (reader.IsEOF) + throw reader.ThrowEOF('-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + if (reader.Char == '-') + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + } + + if (reader.Char < '0' || '9' < reader.Char) + throw reader.ThrowFormat('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + while (true) + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + if (reader.Char < '0' || '9' < reader.Char) + break; + } + + if (reader.Char == '.') + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + if (reader.Char < '0' || '9' < reader.Char) + throw reader.ThrowFormat('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + while (true) + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + if (reader.Char < '0' || '9' < reader.Char) + break; + } + } + + if (reader.Char == 'e' || reader.Char == 'E') + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('+', '-', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + bool signed = false; + if (reader.Char == '+') + { + reader.ReadNext(); + signed = true; + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + } + else if (reader.Char == '-') + { + reader.ReadNext(); + signed = true; + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + } + + if (reader.Char < '0' || '9' < reader.Char) + { + if (signed) + throw reader.ThrowFormat('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + else + throw reader.ThrowFormat('-', '+', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + } + + while (true) + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9'); + + if (reader.Char < '0' || '9' < reader.Char) + break; + } + } + + string value = reader.Substring(startPos, reader.Position - startPos); + + return double.Parse(value, format); + } + + private static string ReadValueString(JsonTextReader reader) + { + if (reader.IsEOF) + throw reader.ThrowEOF('"'); + else if (reader.Char != '"') + throw reader.ThrowFormat('"'); + + reader.ReadNext(); + + StringBuilder sb = new StringBuilder(); + while (true) + { + if (reader.IsEOF) + throw reader.ThrowEOF('"'); + + if (reader.Char == '"') + break; + else if (reader.Char == '\\') + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('"', '\\', '/', 'b', 'f', 'n', 'r', 't', 'u'); + switch (reader.Char) + { + case '"': sb.Append('"'); break; + case '\\': sb.Append('\\'); break; + case '/': sb.Append('/'); break; + case 'b': sb.Append('\b'); break; + case 'f': sb.Append('\f'); break; + case 'n': sb.Append('\n'); break; + case 'r': sb.Append('\r'); break; + case 't': sb.Append('\t'); break; + case 'u': + int number = 0; + for (int i = 0; i < 4; i++) + { + reader.ReadNext(); + if (reader.IsEOF) + throw reader.ThrowEOF('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'); + if ('0' <= reader.Char && reader.Char <= '9') + { + number = number * 0x10 + (int)(reader.Char - '0'); + } + else if ('a' <= reader.Char && reader.Char <= 'f') + { + number = number * 0x10 + 10 + (int)(reader.Char - 'a'); + } + else if ('A' <= reader.Char && reader.Char <= 'F') + { + number = number * 0x10 + 10 + (int)(reader.Char - 'A'); + } + else + { + throw reader.ThrowFormat('0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F'); + } + } + + sb.Append((char)number); + + break; + + default: + throw reader.ThrowFormat('"', '\\', '/', 'b', 'f', 'n', 'r', 't', 'u'); + } + } + else + { + sb.Append(reader.Char); + } + + reader.ReadNext(); + } + + reader.ReadNext(); + + return sb.ToString(); + } + + private bool IsNumber(StringBuilder sb, object item) + { + return item is float + || item is double + || item is sbyte + || item is byte + || item is short + || item is ushort + || item is int + || item is uint + || item is long + || item is ulong + || item is decimal; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonParser/JsonObject.cs b/FastReport.Base/Data/JsonConnection/JsonParser/JsonObject.cs new file mode 100644 index 00000000..0ad03e1b --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonParser/JsonObject.cs @@ -0,0 +1,118 @@ +using System.Collections; +using System.Collections.Generic; +using System.Text; + +namespace FastReport.Data.JsonConnection.JsonParser +{ + internal class JsonObject : JsonBase, IEnumerable> + { + #region Private Fields + + private Dictionary dict = new Dictionary(); + + #endregion Private Fields + + #region Public Indexers + + public override object this[string key] + { + get + { + object result; + if (dict.TryGetValue(key, out result)) + return result; + return null; + } + set + { + dict[key] = value; + } + } + + #endregion Public Indexers + + #region Public Properties + + public override int Count + { + get + { + return dict.Count; + } + } + + public override bool IsObject + { + get + { + return true; + } + } + + public override IEnumerable Keys + { + get + { + return dict.Keys; + } + } + + #endregion Public Properties + + #region Public Methods + + public override bool ContainsKey(string key) + { + return dict.ContainsKey(key); + } + + public bool DeleteKey(string key) + { + return dict.Remove(key); + } + + public IEnumerator> GetEnumerator() + { + return dict.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return dict.GetEnumerator(); + } + + public override void WriteTo(StringBuilder sb, int indent) + { + sb.Append("{"); + bool notFirst = false; + foreach (KeyValuePair kv in dict) + { + if (notFirst) + sb.Append(","); + if (indent > 0) + { + sb.AppendLine(); + for (int i = 0; i < indent; i++) + sb.Append(' '); + } + + WriteValue(sb, kv.Key, indent); + if (indent > 0) + sb.Append(": "); + else + sb.Append(":"); + WriteValue(sb, kv.Value, indent); + notFirst = true; + } + if (indent > 0 && notFirst) + { + sb.AppendLine(); + for (int i = 2; i < indent; i++) + sb.Append(' '); + } + sb.Append("}"); + } + + #endregion Public Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonParser/JsonSchema.cs b/FastReport.Base/Data/JsonConnection/JsonParser/JsonSchema.cs new file mode 100644 index 00000000..2daffd9f --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonParser/JsonSchema.cs @@ -0,0 +1,233 @@ +using System; +using System.Collections.Generic; + +namespace FastReport.Data.JsonConnection.JsonParser +{ + internal class JsonSchema + { + #region Private Fields + + private string description; + private JsonSchema items; + private Dictionary properties; + private string type; + + #endregion Private Fields + + #region Public Properties + + public Type DataType + { + get + { + switch (type) + { + case "object": return typeof(JsonBase); + case "array": return typeof(JsonBase); + case "integer": return typeof(int); + case "number": return typeof(double); + case "string": return typeof(string); + case "boolean": return typeof(bool); + default: return typeof(object); + } + } + } + + public string Description { get { return description; } set { description = value; } } + + public JsonSchema Items + { + get + { + return items; + } + set + { + items = value; + } + } + + public Dictionary Properties + { + get + { + return properties; + } + } + + public string Type { get { return type; } set { type = value; } } + + #endregion Public Properties + + #region Public Methods + + public static JsonSchema FromJson(object json) + { + JsonSchema result = new JsonSchema(); + if (json is JsonObject) + { + result.type = "object"; + result.properties = new Dictionary(); + + foreach (KeyValuePair kv in (json as JsonObject)) + { + result.Properties[kv.Key] = FromJson(kv.Value); + } + } + else if (json is JsonArray) + { + result.Type = "array"; + result.items = null; + foreach (object obj in (json as JsonArray)) + { + JsonSchema sub = FromJson(obj); + if (result.items == null) + result.items = sub; + else result.items.Union(sub); + } + + if (result.items == null) + result.items = new JsonSchema(); + } + else if (json is string) + { + result.Type = "string"; + } + else if (json is double) + { + result.Type = "number"; + } + else if (json is bool) + { + result.Type = "boolean"; + } + else + { + result.Type = "null"; + } + return result; + } + + public static JsonSchema Load(JsonObject obj) + { + if (obj == null) + { + throw new NullReferenceException("Unable to load schema from non-object"); + } + + JsonSchema result = new JsonSchema(); + if (obj != null) + { + result.Type = obj.ReadString("type"); + result.Description = obj.ReadString("description"); + switch (result.Type) + { + case "object": + result.properties = new Dictionary(); + if (obj.ContainsKey("properties")) + { + JsonObject child = obj["properties"] as JsonObject; + if (child != null) + { + foreach (KeyValuePair kv in child) + { + if (kv.Value is JsonObject) + { + result.Properties[kv.Key] = Load(kv.Value as JsonObject); + } + else + { + result.Properties[kv.Key] = new JsonSchema(); + } + } + } + } + break; + + case "array": + if (obj.ContainsKey("items")) + result.items = Load(obj["items"] as JsonObject); + else + result.items = new JsonSchema(); + break; + } + } + + return result; + } + + public void Save(JsonObject obj) + { + if (Type != null) + { + obj["type"] = Type; + } + if (Description != null) + { + obj["description"] = Description; + } + + if (Items != null) + { + JsonObject child = new JsonObject(); + Items.Save(child); + obj["items"] = child; + } + + if (Properties != null && Properties.Count > 0) + { + JsonObject child = new JsonObject(); + obj["properties"] = child; + foreach (KeyValuePair kv in Properties) + { + JsonObject sub_child = new JsonObject(); + kv.Value.Save(sub_child); + child[kv.Key] = sub_child; + } + } + } + + #endregion Public Methods + + #region Private Methods + + private void Union(JsonSchema sub) + { + if (sub == null || type != sub.type) + { + items = null; + properties = null; + type = "null"; + } + else if (type == "object") + { + if (properties == null) + properties = new Dictionary(); + if (sub.Properties != null) + foreach (KeyValuePair kv in sub.Properties) + { + JsonSchema child; + if (Properties.TryGetValue(kv.Key, out child)) + { + child.Union(kv.Value); + } + else + { + Properties[kv.Key] = kv.Value; + } + } + } + else if (type == "array") + { + if (items == null) + items = sub.items; + else + { + items.Union(sub.items); + } + } + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonParser/JsonTextReader.cs b/FastReport.Base/Data/JsonConnection/JsonParser/JsonTextReader.cs new file mode 100644 index 00000000..797d8b08 --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonParser/JsonTextReader.cs @@ -0,0 +1,148 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FastReport.Data.JsonConnection.JsonParser +{ + internal class JsonTextReader : IDisposable + { + #region Private Fields + + private string jsonText; + private Dictionary pool = new Dictionary(); + private int position; + private bool stringOptimization; + + #endregion Private Fields + + #region Public Properties + + public char Char + { + get + { + return jsonText[position]; + } + } + + public bool IsEOF + { + get + { + return position >= jsonText.Length; + } + } + + public bool IsNotEOF + { + get + { + return position < jsonText.Length; + } + } + + public string JsonText + { + get { return jsonText; } + set { jsonText = value; } + } + + public int Position + { + get { return position; } + set { position = value; } + } + + #endregion Public Properties + + #region Public Constructors + + public JsonTextReader(string jsonText) + { + stringOptimization = Utils.Config.IsStringOptimization; + + this.jsonText = jsonText; + position = 0; + } + + #endregion Public Constructors + + #region Public Methods + + public string Dedublicate(string value) + { + if (stringOptimization) + { + string result; + if (pool.TryGetValue(value, out result)) + return result; + return pool[value] = value; + } + return value; + } + + public void Dispose() + { + JsonText = null; + pool.Clear(); + pool = null; + } + + public void ReadNext() + { + position++; + } + + public void SkipWhiteSpace() + { + while (IsNotEOF && char.IsWhiteSpace(Char)) + position++; + } + + public Exception ThrowEOF(params char[] args) + { + StringBuilder sb = new StringBuilder(); + sb.Append("Unexpected end of input json, wait for"); + if (args.Length > 0) + { + sb.Append(" ").Append(args[0]); + } + for (int i = 1; i < args.Length; i++) + { + sb.Append(", ").Append(args[i]); + } + return new FormatException(sb.ToString()); + } + + public Exception ThrowEOF(string args) + { + return new FormatException("Unexpected end of input json, wait for " + args); + } + + public Exception ThrowFormat(params char[] args) + { + StringBuilder sb = new StringBuilder(); + sb.Append("Json text at position ").Append(Position).Append(", unexpected symbol ").Append(Char).Append(", wait for"); + if (args.Length > 0) + { + sb.Append(" ").Append(args[0]); + } + for (int i = 1; i < args.Length; i++) + { + sb.Append(", ").Append(args[i]); + } + return new FormatException(sb.ToString()); + } + + #endregion Public Methods + + #region Internal Methods + + internal string Substring(int startPos, int len) + { + return JsonText.Substring(startPos, len); + } + + #endregion Internal Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs b/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs new file mode 100644 index 00000000..c65722df --- /dev/null +++ b/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs @@ -0,0 +1,352 @@ +using FastReport.Data.JsonConnection.JsonParser; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace FastReport.Data.JsonConnection +{ + /// + /// JsonTableDataSource present a json array object + /// + public class JsonTableDataSource : TableDataSource + { + #region Private Fields + + private JsonArray _json; + private bool updateSchema; + + #endregion Private Fields + + #region Public Properties + + /// + /// Gets or sets value for force update schema on init schema + /// + public bool UpdateSchema + { + get + { + return updateSchema; + } + set + { + updateSchema = value; + } + } + + #endregion Public Properties + + #region Internal Properties + + internal JsonArray Json + { + get + { + if (_json == null) + { + _json = GetJson(Parent, this) as JsonArray; + if (_json == null) + _json = new JsonArray(); + } + return _json; + } + set + { + _json = value; + } + } + + #endregion Internal Properties + + #region Private Properties + + private int CurrentIndex + { + get + { + if (currentRow is int) + return (int)currentRow; + if (CurrentRowNo < Rows.Count) + { + object result = Rows[CurrentRowNo]; + if (result is int) + return (int)result; + } + return CurrentRowNo; + } + } + + #endregion Private Properties + + #region Public Constructors + + /// + public JsonTableDataSource() + { + DataType = typeof(JsonArray); + } + + #endregion Public Constructors + + #region Public Methods + + /// + public override void InitializeComponent() + { + base.InitializeComponent(); + Json = null; + } + + /// + public override void InitSchema() + { + if (Columns.Count == 0 || UpdateSchema) + { + if (Connection is JsonDataSourceConnection) + { + JsonDataSourceConnection con = Connection as JsonDataSourceConnection; + + InitSchema(this, con.JsonSchema); + } + } + UpdateSchema = false; + } + + /// + public override void LoadData(ArrayList rows) + { + Json = null; + if ( rows != null) + { + rows.Clear(); + int count = Json.Count; + for (int i = 0; i < count; i++) + { + rows.Add(i); + } + } + } + + #endregion Public Methods + + #region Internal Methods + + internal static object GetJsonBaseByColumn(Base parentColumn, Column column) + { + if (parentColumn is JsonTableDataSource) + { + switch (column.PropName) + { + case "item": + return (parentColumn as JsonTableDataSource).Json[(parentColumn as JsonTableDataSource).CurrentIndex]; + } + JsonTableDataSource source = column as JsonTableDataSource; + return source.Json; + } + if (parentColumn is Column && !String.IsNullOrEmpty(column.PropName)) + { + object json = GetJsonBaseByColumn(parentColumn.Parent, parentColumn as Column); + if (json is JsonBase) + { + return (json as JsonBase)[column.PropName]; + } + } + + return null; + } + + internal static object GetValueByColumn(Base parentColumn, Column column) + { + if (parentColumn is JsonTableDataSource) + { + switch (column.PropName) + { + case "index": + return (parentColumn as JsonTableDataSource).CurrentIndex; + + case "array": + return (parentColumn as JsonTableDataSource).Json; + } + } + + object json = GetJsonBaseByColumn(parentColumn, column); + + return json; + } + + internal static void InitSchema(Column table, JsonSchema schema) + { + List saveColumns = new List(); + switch (schema.Type) + { + case "object": + foreach (KeyValuePair kv in schema.Properties) + { + if (kv.Value.Type == "object") + { + Column c = new Column(); + c.Name = kv.Key; + c.Alias = kv.Key; + c.PropName = kv.Key; + c.DataType = kv.Value.DataType; + c = UpdateColumn(table, c, saveColumns); + InitSchema(c, kv.Value); + } + else if (kv.Value.Type == "array") + { + Column c = new JsonTableDataSource(); + c.Name = kv.Key; + c.Alias = kv.Key; + c.PropName = kv.Key; + c.DataType = kv.Value.DataType; + c = UpdateColumn(table, c, saveColumns); + InitSchema(c, kv.Value); + } + else + { + Column c = new Column(); + c.Name = kv.Key; + c.Alias = kv.Key; + c.PropName = kv.Key; + c.DataType = kv.Value.DataType; + c.SetBindableControlType(c.DataType); + UpdateColumn(table, c, saveColumns); + } + } + break; + + case "array": + JsonSchema items = schema.Items; + { + Column c = new Column(); + c.Name = "index"; + c.Alias = "index"; + c.PropName = "index"; + c.DataType = typeof(int); + UpdateColumn(table, c, saveColumns); + } + + { + Column c; + bool iSchema = false; + + if (items.Type == "object") + { + c = new Column(); + iSchema = true; + + } + else if (items.Type == "array") + { + c = new JsonTableDataSource(); + iSchema = true; + } + else + { + c = new Column(); + } + + c.Name = "item"; + c.Alias = "item"; + c.PropName = "item"; + c.DataType = items.DataType; + c = UpdateColumn(table, c, saveColumns); + + if (iSchema) + InitSchema(c, items); + } + + { + Column c = new Column(); + c.Name = "array"; + c.Alias = "array"; + c.PropName = "array"; + c.DataType = typeof(JsonBase); + UpdateColumn(table, c, saveColumns); + } + break; + } + + for (int i = 0; i < table.Columns.Count; i++) + { + if (!(table.Columns[i].Calculated || saveColumns.Contains(table.Columns[i]))) + { + table.Columns.RemoveAt(i); + i--; + } + } + } + + internal object GetJson(Base parentColumn, Column column) + { + if (parentColumn is JsonDataSourceConnection) + { + // return zero level json + return (parentColumn as JsonDataSourceConnection).Json; + } + else if (parentColumn is JsonTableDataSource) + { + JsonTableDataSource source = parentColumn as JsonTableDataSource; + return source.Json[source.CurrentRowNo] as object; + } + else if (parentColumn is Column) + { + object parentJson = GetJson(parentColumn.Parent, parentColumn as Column); + if (parentJson is JsonBase && !String.IsNullOrEmpty(column.PropName)) + { + return (parentJson as JsonBase)[column.PropName]; + } + } + return null; + } + + #endregion Internal Methods + + #region Protected Methods + + /// + protected override object GetValue(Column column) + { + return GetValueByColumn(column.Parent, column); + } + + /// + protected override object GetValue(string alias) + { + // TODO TEST + Column column = this; + string[] colAliases = alias.Split(new char[] { '.' }); + + foreach (string colAlias in colAliases) + { + column = column.Columns.FindByAlias(colAlias); + if (column == null) + return null; + } + + return GetValueByColumn(column.Parent, column); + } + + #endregion Protected Methods + + #region Private Methods + + private static Column UpdateColumn(Column table, Column c, List list) + { + foreach (Column child in table.Columns) + { + if (child.PropName == c.PropName) + { + child.DataType = c.DataType; + list.Add(child); + return child; + } + } + table.AddChild(c); + list.Add(c); + return c; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Engine/ReportEngine.Bands.cs b/FastReport.Base/Engine/ReportEngine.Bands.cs index acfebd64..b6ea3b05 100644 --- a/FastReport.Base/Engine/ReportEngine.Bands.cs +++ b/FastReport.Base/Engine/ReportEngine.Bands.cs @@ -139,15 +139,15 @@ private void ShowBand(BandBase band, BandBase outputBand, float offsetX, float o /// public void ShowBand(BandBase band) { - ShowBand(band, true); + if (band != null) + for (int i = 0; i < band.RepeatBandNTimes; i++) + ShowBand(band, true); } private void ShowBand(BandBase band, bool getData) { if (band == null) - { return; - } BandBase saveCurBand = curBand; curBand = band; diff --git a/FastReport.Base/Engine/ReportEngine.PageNumbers.cs b/FastReport.Base/Engine/ReportEngine.PageNumbers.cs index 0d5647d6..b59ac0f5 100644 --- a/FastReport.Base/Engine/ReportEngine.PageNumbers.cs +++ b/FastReport.Base/Engine/ReportEngine.PageNumbers.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; namespace FastReport.Engine { @@ -10,10 +10,15 @@ private class PageNumberInfo { #region Fields - public int pageNo; + public readonly int pageNo; public int totalPages; #endregion Fields + + public PageNumberInfo(int pageNo) + { + this.pageNo = pageNo; + } } #endregion Private Classes @@ -74,9 +79,25 @@ internal void IncLogicalPageNumber() int index = CurPage - firstReportPage; if (FirstPass || index >= pageNumbers.Count) { - PageNumberInfo info = new PageNumberInfo(); + PageNumberInfo info = new PageNumberInfo(logicalPageNo); pageNumbers.Add(info); - info.pageNo = logicalPageNo; + } + } + + + /// + /// Called when the number of pages increased during DoublePass + /// + internal void ShiftLastPage() + { + PageNumberInfo info = new PageNumberInfo(pageNumbers.Count + 1); + pageNumbers.Add(info); + + + for (int i = pageNumbers.Count - 1; i >= 0; i--) + { + info = pageNumbers[i]; + info.totalPages = pageNumbers.Count; } } diff --git a/FastReport.Base/Engine/ReportEngine.Pages.cs b/FastReport.Base/Engine/ReportEngine.Pages.cs index 0bdda6b8..32cd364c 100644 --- a/FastReport.Base/Engine/ReportEngine.Pages.cs +++ b/FastReport.Base/Engine/ReportEngine.Pages.cs @@ -100,9 +100,17 @@ private void ShowPageHeader() ShowBand(page.PageHeader); } - private void ShowPageFooter() + private void ShowPageFooter(bool startPage) { - ShowBand(page.PageFooter); + if (!FirstPass && + (page.PageFooter.PrintOn & PrintOn.LastPage) > 0 && + CurPage == TotalPages - 1 && + startPage) + { + ShiftLastPage(); + } + else + ShowBand(page.PageFooter); } private bool StartFirstPage() @@ -245,7 +253,7 @@ private void EndLastPage() ShowBand(page.ColumnFooter); } - ShowPageFooter(); + ShowPageFooter(false); OutlineRoot(); page.FinalizeComponents(); } @@ -351,7 +359,7 @@ private void StartPage() internal void EndPage(bool startPage) { OnStateChanged(page, EngineState.PageFinished); - ShowPageFooter(); + ShowPageFooter(startPage); if (Report.MaxPages > 0 && PreparedPages.Count >= Report.MaxPages) Report.Abort(); diff --git a/FastReport.Base/Export/Html/HTMLExport.cs b/FastReport.Base/Export/Html/HTMLExport.cs index f8161703..c6dab280 100644 --- a/FastReport.Base/Export/Html/HTMLExport.cs +++ b/FastReport.Base/Export/Html/HTMLExport.cs @@ -135,10 +135,23 @@ public enum ExportType private ExportType exportMode; private bool enableVectorObjects = true; + /// + /// hash:base64Image + /// + private Dictionary embeddedImages; #endregion Private fields #region Public properties + /// + /// Gets or sets images, embedded in html (hash:base64Image) + /// + public Dictionary EmbeddedImages + { + get { return embeddedImages; } + set { embeddedImages = value; } + } + /// /// Sets a ID of report /// @@ -972,6 +985,7 @@ public HTMLExport() numberFormat.NumberDecimalSeparator = "."; exportMode = ExportType.Export; res = new MyRes("Export,Html"); + embeddedImages = new Dictionary(); } } diff --git a/FastReport.Base/Export/Html/HTMLExportDraw.cs b/FastReport.Base/Export/Html/HTMLExportDraw.cs index d507ad52..a671b8ca 100644 --- a/FastReport.Base/Export/Html/HTMLExportDraw.cs +++ b/FastReport.Base/Export/Html/HTMLExportDraw.cs @@ -6,9 +6,6 @@ namespace FastReport.Export.Html { - /// - /// Represents the HTML export filter. - /// public partial class HTMLExport : ExportBase { private void HTMLFontStyle(FastString FFontDesc, Font font, float LineHeight) @@ -319,7 +316,7 @@ private string HTMLGetImage(int PageNumber, int CurrentPage, int ImageNumber, st } if (EmbedPictures && PictureStream != null) { - return embedPreffix + Convert.ToBase64String(PictureStream.ToArray()); + return embedPreffix + GetBase64Image(PictureStream, hash); } else if (subFolder && singlePage && !navigator) return ExportUtils.HtmlURL(subFolderPath + ImageFileName); @@ -330,7 +327,7 @@ private string HTMLGetImage(int PageNumber, int CurrentPage, int ImageNumber, st { if (EmbedPictures) { - return embedPreffix + Convert.ToBase64String(PictureStream.ToArray()); + return embedPreffix + GetBase64Image(PictureStream, hash); } else { @@ -351,5 +348,16 @@ private string HTMLGetImage(int PageNumber, int CurrentPage, int ImageNumber, st else return String.Empty; } + + private string GetBase64Image(MemoryStream PictureStream, string hash) + { + string base64Image = String.Empty; + if (!EmbeddedImages.TryGetValue(hash, out base64Image)) + { + base64Image = Convert.ToBase64String(PictureStream.ToArray()); + EmbeddedImages.Add(hash, base64Image); + } + return base64Image; + } } } diff --git a/FastReport.Base/Export/Html/HTMLExportLayers.cs b/FastReport.Base/Export/Html/HTMLExportLayers.cs index d3ecb7a0..8235cd07 100644 --- a/FastReport.Base/Export/Html/HTMLExportLayers.cs +++ b/FastReport.Base/Export/Html/HTMLExportLayers.cs @@ -7,9 +7,6 @@ namespace FastReport.Export.Html { - /// - /// Represents the HTML export filter. - /// public partial class HTMLExport : ExportBase { private bool doPageBreak; @@ -189,7 +186,7 @@ private void Layer(FastString Page, ReportComponentBase obj, private string EncodeURL(string value) { -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 return System.Net.WebUtility.UrlEncode(value); #else return ExportUtils.HtmlURL(value); @@ -516,6 +513,7 @@ private string GetLayerPicture(ReportComponentBase obj, out float Width, out flo obj.Border.Lines = BorderLines.None; obj.Draw(new FRPaintEventArgs(g, Zoom, Zoom, Report.GraphicCache)); obj.Border.Lines = oldLines; + } if (FPictureFormat == System.Drawing.Imaging.ImageFormat.Jpeg) @@ -524,7 +522,38 @@ private string GetLayerPicture(ReportComponentBase obj, out float Width, out flo image.Save(PictureStream, FPictureFormat); } PictureStream.Position = 0; - result = HTMLGetImage(0, 0, 0, Crypter.ComputeHash(PictureStream), true, null, PictureStream, false); + + string hash = String.Empty; + if (obj is PictureObject) + { + PictureObject pic = (obj as PictureObject); + if (pic.Image == null) + { + + } + else + { + using (MemoryStream picStr = new MemoryStream()) + { + + ImageHelper.Save(pic.Image, picStr); + using(StreamWriter picWriter = new StreamWriter(picStr)) + { + picWriter.Write(pic.Width); + picWriter.Write(pic.Height); + picWriter.Write(pic.Angle); + picWriter.Write(pic.Transparency); + picWriter.Write(pic.TransparentColor.ToArgb()); + picWriter.Write(pic.CanShrink); + picWriter.Write(pic.CanGrow); + hash = Crypter.ComputeHash(picStr); + } + } + } + } + else + hash = Crypter.ComputeHash(PictureStream); + result = HTMLGetImage(0, 0, 0, hash, true, null, PictureStream, false); } } return result; @@ -535,7 +564,6 @@ private void LayerPicture(FastString Page, ReportComponentBase obj, FastString t if (pictures) { int styleindex = UpdateCSSTable(obj); - string style = GetStyleTag(styleindex); string old_text = String.Empty; if (IsMemo(obj)) @@ -550,8 +578,18 @@ private void LayerPicture(FastString Page, ReportComponentBase obj, FastString t if (IsMemo(obj)) (obj as TextObject).Text = old_text; - FastString addstyle = new FastString(128); - addstyle.Append(" background: url('").Append(pic).Append("') no-repeat !important;-webkit-print-color-adjust:exact;"); + FastString picStyleBuilder = new FastString("background: url('") + .Append(pic).Append("') no-repeat !important;-webkit-print-color-adjust:exact;"); + + int picStyleIndex = UpdateCSSTable(picStyleBuilder.ToString()); + + + string style = String.Format("class=\"{0}s{1} {0}s{2}\"", + stylePrefix, + styleindex.ToString(), picStyleIndex.ToString()); + + //FastString addstyle = new FastString(128); + //addstyle.Append(" background: url('").Append(pic).Append("') no-repeat !important;-webkit-print-color-adjust:exact;"); //if (String.IsNullOrEmpty(text)) // text = NBSP; @@ -559,12 +597,10 @@ private void LayerPicture(FastString Page, ReportComponentBase obj, FastString t float x = Width > 0 ? obj.AbsLeft : (obj.AbsLeft + Width); float y = Height > 0 ? hPos + obj.AbsTop : (hPos + obj.AbsTop + Height); - Layer(Page, obj, x, y, Width, Height, text, style, addstyle); + Layer(Page, obj, x, y, Width, Height, text, style, null); } } - - private void LayerShape(FastString Page, ShapeObject obj, FastString text) { int styleindex = UpdateCSSTable(obj); @@ -614,10 +650,13 @@ private void LayerBack(FastString Page, ReportComponentBase obj, FastString text } } - if (obj.Fill is SolidFill) - Layer(Page, obj, obj.AbsLeft, hPos + obj.AbsTop, obj.Width, obj.Height, text, GetStyleTag(UpdateCSSTable(obj)), null); - else - LayerPicture(Page, obj, text); + if (!(obj is PolyLineObject)) + { + if (obj.Fill is SolidFill) + Layer(Page, obj, obj.AbsLeft, hPos + obj.AbsTop, obj.Width, obj.Height, text, GetStyleTag(UpdateCSSTable(obj)), null); + else + LayerPicture(Page, obj, text); + } } private void LayerTable(FastString Page, FastString CSS, TableBase table) @@ -723,6 +762,7 @@ private void ExportHTMLPageLayeredBegin(HTMLData d) maxWidth = ExportUtils.GetPageWidth(reportPage) * Units.Millimeters; maxHeight = ExportUtils.GetPageHeight(reportPage) * Units.Millimeters; + if (enableMargins) { leftMargin = reportPage.LeftMargin * Units.Millimeters; @@ -745,8 +785,21 @@ private void ExportHTMLPageLayeredBegin(HTMLData d) htmlPage.Append(HTMLGetAncor((d.PageNumber).ToString())); htmlPage.Append("
- /// Represents the HTML export filter. - /// public partial class HTMLExport : ExportBase { private string Px(double pixel) diff --git a/FastReport.Base/Gauge/GaugeLabel.cs b/FastReport.Base/Gauge/GaugeLabel.cs index ac24876d..2d6c54b3 100644 --- a/FastReport.Base/Gauge/GaugeLabel.cs +++ b/FastReport.Base/Gauge/GaugeLabel.cs @@ -138,7 +138,7 @@ public virtual void Serialize(FRWriter writer, string prefix, GaugeLabel diff) { writer.WriteStr(prefix + ".Text", Text); } - if (writer.SerializeTo != SerializeTo.Preview || !Font.Equals(diff.Font)) + if ((writer.SerializeTo != SerializeTo.Preview || !Font.Equals(diff.Font)) && writer.ItemName != "inherited") { writer.WriteValue(prefix + ".Font", Font); } diff --git a/FastReport.Base/Gauge/GaugeScale.cs b/FastReport.Base/Gauge/GaugeScale.cs index 41d48ea8..0d858a2c 100644 --- a/FastReport.Base/Gauge/GaugeScale.cs +++ b/FastReport.Base/Gauge/GaugeScale.cs @@ -122,7 +122,7 @@ public virtual void Draw(FRPaintEventArgs e) public virtual void Serialize(FRWriter writer, string prefix, GaugeScale diff) { TextFill.Serialize(writer, prefix + ".TextFill", diff.TextFill); - if (writer.SerializeTo != SerializeTo.Preview || !Font.Equals(diff.Font)) + if ((writer.SerializeTo != SerializeTo.Preview || !Font.Equals(diff.Font)) && writer.ItemName != "inherited") { writer.WriteValue(prefix + ".Font", Font); } diff --git a/FastReport.Base/GroupHeaderBand.cs b/FastReport.Base/GroupHeaderBand.cs index 87862a07..aac575cd 100644 --- a/FastReport.Base/GroupHeaderBand.cs +++ b/FastReport.Base/GroupHeaderBand.cs @@ -287,7 +287,7 @@ public override bool CanContain(Base child) { return base.CanContain(child) || (child is DataBand && nestedGroup == null && data == null) || - (child is GroupHeaderBand && nestedGroup == null && data == null) || + (child is GroupHeaderBand && (nestedGroup == null || nestedGroup is GroupHeaderBand) && data == null) || child is GroupFooterBand || child is DataHeaderBand || child is DataFooterBand; } diff --git a/FastReport.Base/PictureObject.cs b/FastReport.Base/PictureObject.cs index 3cc4e0c1..f88570fb 100644 --- a/FastReport.Base/PictureObject.cs +++ b/FastReport.Base/PictureObject.cs @@ -482,9 +482,9 @@ public override void LoadImage() { Uri uri = CalculateUri(); if (uri.IsFile) - imageData = ImageHelper.Load(uri.LocalPath); + SetImageData(ImageHelper.Load(uri.LocalPath)); else - imageData = ImageHelper.LoadURL(uri.ToString()); + SetImageData(ImageHelper.LoadURL(uri.ToString())); } catch { diff --git a/FastReport.Base/PictureObjectBase.cs b/FastReport.Base/PictureObjectBase.cs index 55c3a658..84668733 100644 --- a/FastReport.Base/PictureObjectBase.cs +++ b/FastReport.Base/PictureObjectBase.cs @@ -762,7 +762,7 @@ internal virtual void DrawImageInternal(FRPaintEventArgs e, RectangleF drawRect) // TODO translate tranform matrix, WTF mono or coreCompat or both // cant work with negative transforms so need to fix it -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 System.Drawing.Drawing2D.Matrix matrixBack = e.Graphics.Transform; @@ -789,7 +789,7 @@ internal virtual void DrawImageInternal(FRPaintEventArgs e, RectangleF drawRect) DrawImageInternal2(e.Graphics, upperLeft, upperRight, lowerLeft); -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 e.Graphics.Transform = matrixBack; #endif } diff --git a/FastReport.Base/PolyLineObject.cs b/FastReport.Base/PolyLineObject.cs index 9052eb5d..a74b391d 100644 --- a/FastReport.Base/PolyLineObject.cs +++ b/FastReport.Base/PolyLineObject.cs @@ -1,5 +1,6 @@ using FastReport.Utils; using System; +using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; @@ -18,13 +19,36 @@ namespace FastReport /// public partial class PolyLineObject : ReportComponentBase { - #region Fields + #region Protected Internal Fields + + /// + /// do not set this value, internal use only + /// + protected internal PolygonSelectionMode polygonSelectionMode; + + #endregion Protected Internal Fields + + #region Private Fields + private PointF center; - private List points; - private List pointTypes; - #endregion Fields + private PolyPointCollection pointsCollection; + + #endregion Private Fields + + #region Public Properties + + /// + /// Return points collection. + /// You can modify the collection for change this object. + /// + public PolyPointCollection Points + { + get + { + return pointsCollection; + } + } - #region Properties /// /// Returns origin of coordinates relative to the top left corner /// @@ -39,110 +63,134 @@ public partial class PolyLineObject : ReportComponentBase /// /// Return points array of line + /// deprecated /// [Browsable(false)] + [Obsolete] public PointF[] PointsArray { get { - if (points == null || points.Count == 0) return new PointF[0]; - return points.ToArray(); + List result = new List(); + foreach (PolyPoint point in pointsCollection) + { + result.Add(new PointF(point.X, point.Y)); + } + return result.ToArray(); } } /// /// Return point types array. 0 - Start of line, 1 - Keep on line + /// deprecated /// [Browsable(false)] + [Obsolete] public byte[] PointTypesArray { get { - if (pointTypes == null || pointTypes.Count == 0) return new byte[0]; - return pointTypes.ToArray(); + List result = new List(); + result.Add(0); + for (int i = 1; i < pointsCollection.Count; i++) + result.Add(1); + return result.ToArray(); } } - #endregion Properties - #region Private Methods - private float getDistance(float px, float py, float px0, float py0, float px1, float py1, out int index) - { - float vx = px1 - px0; - float vy = py1 - py0; - float wx = px - px0; - float wy = py - py0; - float c1 = vx * wx + vy * wy; - if (c1 <= 0) { index = -1; return (px0 - px) * (px0 - px) + (py0 - py) * (py0 - py); } - float c2 = vx * vx + vy * vy; - if (c2 <= c1) { index = 1; return (px1 - px) * (px1 - px) + (py1 - py) * (py1 - py); } - float b = c1 / c2; - index = 0; - float bx = px0 + vx * b; - float by = py0 + vy * b; - return (bx - px) * (bx - px) + (by - py) * (by - py); - } - #endregion Private Methods + #endregion Public Properties + + #region Public Constructors - #region Protected Methods /// - /// Add point to end of polyline, need to recalculate bounds after add - /// First point must have zero coordinate and zero type + /// Initializes a new instance of the class with default settings. /// - /// local x - relative to left-top point - /// local y - relative to left-top point - /// 0-start,1-line - protected void addPoint(float localX, float localY, byte pointType) + public PolyLineObject() { - if (points == null) - { - points = new List(); - points.Add(new PointF(localX, localY)); - } - else - { - points.Add(new PointF(localX, localY)); - } - if (pointTypes == null) - { - pointTypes = new List(); - pointTypes.Add((byte)PathPointType.Start); - } - else - { - pointTypes.Add(pointType); - } + FlagSimpleBorder = true; + FlagUseFill = false; + pointsCollection = new PolyPointCollection(); + center = PointF.Empty; + InitDesign(); } - /// - /// Delete point from polyline by index - /// Recalculate bounds - /// - /// Index of point in polyline - protected void deletePoint(int index) + #endregion Public Constructors + + #region Public Methods + + /// + public override void Assign(Base source) { - if (points == null || points.Count == 0) - return; - if (pointTypes[index] == 0 && index < pointTypes.Count - 1) + base.Assign(source); + + PolyLineObject src = source as PolyLineObject; + + pointsCollection = src.pointsCollection.Clone(); + center = src.center; + //recalculateBounds(); + } + + /// + public override void Deserialize(FRReader reader) + { + base.Deserialize(reader); + pointsCollection.Clear(); + if (reader.HasProperty("PolyPoints")) { - pointTypes[index + 1] = 0; + string polyPoints = reader.ReadStr("PolyPoints"); + foreach (string str in polyPoints.Split('|')) + { + string[] point = str.Split('\\'); + if (point.Length == 3) + { + float f1 = float.Parse(point[0].Replace(',', '.'), CultureInfo.InvariantCulture); + float f2 = float.Parse(point[1].Replace(',', '.'), CultureInfo.InvariantCulture); + pointsCollection.Add(new PolyPoint(f1, f2)); + } + } } - if (points.Count > 1) + else if (reader.HasProperty("PolyPoints_v2")) { - points.RemoveAt(index); - pointTypes.RemoveAt(index); - recalculateBounds(); + string polyPoints = reader.ReadStr("PolyPoints_v2"); + foreach (string str in polyPoints.Split('|')) + { + PolyPoint point = new PolyPoint(); + point.Deserialize(str); + pointsCollection.Add(point); + } } + if (reader.HasProperty("CenterX")) + center.X = reader.ReadFloat("CenterX"); + if (reader.HasProperty("CenterY")) + center.Y = reader.ReadFloat("CenterY"); + //recalculateBounds(); } - /// - /// Draw polyline path to graphics - /// - /// Event arguments - protected virtual void drawPoly(FRPaintEventArgs e) + /// + public override void Draw(FRPaintEventArgs e) { - Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); - using (GraphicsPath path = GetPath(pen, AbsLeft, AbsTop, AbsRight, AbsBottom, e.ScaleX, e.ScaleY)) - e.Graphics.DrawPath(pen, path); + switch (pointsCollection.Count) + { + case 0: + case 1: + Graphics g = e.Graphics; + float x = AbsLeft + CenterX; + float y = AbsTop + CenterY; + if(pointsCollection.Count == 1) + { + x += pointsCollection[0].X; + y += pointsCollection[0].Y; + } + g.DrawLine(Pens.Black, x * e.ScaleX - 6, y * e.ScaleY, x * e.ScaleX + 6, y * e.ScaleY); + g.DrawLine(Pens.Black, x * e.ScaleX, y * e.ScaleY - 6, x * e.ScaleX, y * e.ScaleY + 6); + break; + + default: + DoDrawPoly(e); + DrawDesign0(e); + break; + } + DrawDesign1(e); } /// @@ -158,222 +206,730 @@ protected virtual void drawPoly(FRPaintEventArgs e) /// Always returns a non-empty path public GraphicsPath GetPath(Pen pen, float left, float top, float right, float bottom, float scaleX, float scaleY) { - if (points == null) + if (pointsCollection.Count == 0) { GraphicsPath result = new GraphicsPath(); - result.AddLine(left, top, right + 1, bottom + 1); + result.AddLine(left * scaleX, top * scaleX, (right + 1) * scaleX, (bottom + 1) * scaleX); return result; } - GraphicsPath gp = null; - if (points.Count > 1) + else if (pointsCollection.Count == 1) { - PointF[] aPoints = new PointF[points.Count]; - int i = 0; - foreach (PointF point in points) + GraphicsPath result = new GraphicsPath(); + left = left + CenterX + pointsCollection[0].X; + top = top + CenterY + pointsCollection[0].Y; + result.AddLine(left * scaleX, top * scaleX, (left + 1) * scaleX, (top + 1) * scaleX); + return result; + } + + List aPoints = new List(); + List pointTypes = new List(); + + PolyPoint prev = null; + PolyPoint point = pointsCollection[0]; + + aPoints.Add(new PointF((point.X + left + center.X) * scaleX, (point.Y + top + center.Y) * scaleY)); + pointTypes.Add(0); + + int count = pointsCollection.Count; + if (this is PolygonObject) + { + count++; + } + + for (int i = 1; i < count; i++) + { + prev = point; + point = pointsCollection[i]; + + //is bezier? + if (prev.RightCurve != null || point.LeftCurve != null) + { + if (prev.RightCurve != null) + { + aPoints.Add(new PointF((prev.X + left + center.X + prev.RightCurve.X) * scaleX, (prev.Y + top + center.Y + prev.RightCurve.Y) * scaleY)); + pointTypes.Add(3); + } + else + { + PolyPoint pseudo = GetPseudoPoint(prev, point); + aPoints.Add(new PointF((pseudo.X + left + center.X) * scaleX, (pseudo.Y + top + center.Y) * scaleY)); + pointTypes.Add(3); + } + + if (point.LeftCurve != null) + { + aPoints.Add(new PointF((point.X + left + center.X + point.LeftCurve.X) * scaleX, (point.Y + top + center.Y + point.LeftCurve.Y) * scaleY)); + pointTypes.Add(3); + } + else + { + PolyPoint pseudo = GetPseudoPoint(point, prev); + aPoints.Add(new PointF((pseudo.X + left + center.X) * scaleX, (pseudo.Y + top + center.Y) * scaleY)); + pointTypes.Add(3); + } + + aPoints.Add(new PointF((point.X + left + center.X) * scaleX, (point.Y + top + center.Y) * scaleY)); + pointTypes.Add(3); + } + else { - aPoints[i] = new PointF((point.X + left + center.X) * scaleX, (point.Y + top + center.Y) * scaleY); - i++; + aPoints.Add(new PointF((point.X + left + center.X) * scaleX, (point.Y + top + center.Y) * scaleY)); + pointTypes.Add(1); } - gp = new GraphicsPath(aPoints, pointTypes.ToArray()); } - else gp = new GraphicsPath(); - return gp; + return new GraphicsPath(aPoints.ToArray(), pointTypes.ToArray()); } /// - /// Insert point to desired place of polyline + /// Recalculate position and size of element /// - /// Index of place from zero to count - /// local x - relative to left-top point - /// local y - relative to left-top point - /// 0-start,1-line - protected void insertPoint(int index, float localX, float localY, byte pointType) + public void RecalculateBounds() { - if (points == null || points.Count == 0) + if (pointsCollection.Count > 0) { - addPoint(localX, localY, pointType); - return; + // init + PolyPoint prev = null; + PolyPoint point = pointsCollection[0]; + float left = point.X; + float top = point.Y; + float right = point.X; + float bottom = point.Y; + int count = pointsCollection.Count; + if (this is PolygonObject) + count++; + + // stage 1 calculate min bounds + + foreach (PolyPoint pnt in pointsCollection) + { + if (pnt.X < left) + left = pnt.X; + else if (pnt.X > right) + right = pnt.X; + + if (pnt.Y < top) + top = pnt.Y; + else if (pnt.Y > bottom) + bottom = pnt.Y; + } + + // stage 2 check if one of bezier way point is outside + + for (int i = 1; i < count; i++) + { + prev = point; + point = pointsCollection[i]; + + bool haveToCalculate = false; + + + PolyPoint p_1 = null; + PolyPoint p_2 = null; + + if (prev.RightCurve != null) + { + p_1 = new PolyPoint(prev.X + prev.RightCurve.X, prev.Y + prev.RightCurve.Y); + + if (p_1.X < left) + haveToCalculate = true; + else if (p_1.X > right) + haveToCalculate = true; + + if (p_1.Y < top) + haveToCalculate = true; + else if (p_1.Y > bottom) + haveToCalculate = true; + } + + if (point.LeftCurve != null) + { + p_2 = new PolyPoint(point.X + point.LeftCurve.X, point.Y + point.LeftCurve.Y); + if (p_2.X < left) + haveToCalculate = true; + else if (p_2.X > right) + haveToCalculate = true; + + if (p_2.Y < top) + haveToCalculate = true; + else if (p_2.Y > bottom) + haveToCalculate = true; + } + + if (haveToCalculate) + { + if (p_1 == null) + p_1 = GetPseudoPoint(prev, point); + + if (p_2 == null) + p_2 = GetPseudoPoint(point, prev); + + + // now calculate extrema + + // x + float delta = RecalculateBounds_Delta(prev.X, p_1.X, p_2.X, point.X); + if (delta > 0) + { + delta = (float)Math.Sqrt(delta); + float t_1 = RecalculateBounds_Solve(prev.X, p_1.X, p_2.X, point.X, -delta); + if (0 < t_1 && t_1 < 1) + { + float x = RecalculateBounds_Value(prev.X, p_1.X, p_2.X, point.X, t_1); + if (x < left) + left = x; + else if (x > right) + right = x; + } + float t_2 = RecalculateBounds_Solve(prev.X, p_1.X, p_2.X, point.X, delta); + if (0 < t_2 && t_2 < 1) + { + float x = RecalculateBounds_Value(prev.X, p_1.X, p_2.X, point.X, t_2); + if (x < left) + left = x; + else if (x > right) + right = x; + } + } + + // y + delta = RecalculateBounds_Delta(prev.Y, p_1.Y, p_2.Y, point.Y); + if (delta > 0) + { + delta = (float)Math.Sqrt(delta); + float t_1 = RecalculateBounds_Solve(prev.Y, p_1.Y, p_2.Y, point.Y, -delta); + if (0 < t_1 && t_1 < 1) + { + float y = RecalculateBounds_Value(prev.Y, p_1.Y, p_2.Y, point.Y, t_1); + if (y < top) + top = y; + else if (y > bottom) + bottom = y; + } + float t_2 = RecalculateBounds_Solve(prev.Y, p_1.Y, p_2.Y, point.Y, delta); + if (0 < t_2 && t_2 < 1) + { + float y = RecalculateBounds_Value(prev.Y, p_1.Y, p_2.Y, point.Y, t_2); + if (y < top) + top = y; + else if (y > bottom) + bottom = y; + } + } + + + } + } + + + // update + float centerX = center.X; + float centerY = center.Y; + center.X = -left; + center.Y = -top; + base.Left += left + centerX; + base.Top += top + centerY; + base.Height = bottom - top; + base.Width = right - left; } + else + { + CenterX = 0; + CenterY = 0; + base.Width = 5; + base.Height = 5; + } + } - if (pointTypes.Count > index && pointTypes[index] == 0) { pointTypes[index] = 1; pointType = 0; } - points.Insert(index, new PointF(localX, localY)); - pointTypes.Insert(index, pointType); - //recalculateBounds(); + private float RecalculateBounds_Delta(float p_0,float p_1, float p_2, float p_3) + { + return p_1 * p_1 - p_0 * p_2 - p_1 * p_2 + p_2 * p_2 + p_0 * p_3 - p_1 * p_3; } - /// - /// Recalculate position and size of element - /// - protected void recalculateBounds() + private float RecalculateBounds_Solve(float p_0, float p_1, float p_2, float p_3, float deltaSqrt) { - float left = points[0].X; - float top = points[0].Y; - float right = points[0].X; - float bottom = points[0].Y; + return (p_0 - 2 * p_1 + p_2 + deltaSqrt) / (p_0 - 3 * p_1 + 3 * p_2 - p_3); + } + + private float RecalculateBounds_Value(float p_0, float p_1, float p_2, float p_3, float t) + { + float t1 = 1 - t; + return p_0 * t1 * t1 * t1 + 3 * p_1 * t1 * t1 * t + 3 * p_2 * t1 * t * t + p_3 * t * t * t; + } + + /// + public override void Serialize(FRWriter writer) + { + Border.SimpleBorder = true; + base.Serialize(writer); + PolyLineObject c = writer.DiffObject as PolyLineObject; - foreach (PointF point in points) + StringBuilder sb = new StringBuilder(pointsCollection.Count * 10); + foreach (PolyPoint point in pointsCollection) { - if (point.X < left) - left = point.X; - else if (point.X > right) - right = point.X; - if (point.Y < top) - top = point.Y; - else if (point.Y > bottom) - bottom = point.Y; + point.Serialize(sb); + sb.Append("|"); } - if (Math.Abs(right - left) == 0) + + if (sb.Length > 0) + sb.Length--; + + writer.WriteStr("PolyPoints_v2", sb.ToString()); + + writer.WriteFloat("CenterX", center.X); + writer.WriteFloat("CenterY", center.Y); + } + + public void SetPolyLine(PointF[] newPoints) + { + pointsCollection.Clear(); + if (newPoints != null) { - right += 1; + CenterX = 0; + CenterY = 0; + foreach (PointF point in newPoints) + { + pointsCollection.Add(new PolyPoint(point.X, point.Y)); + } } - if (Math.Abs(bottom - top) == 0) + float l = Left; + float t = Top; + RecalculateBounds(); + Left = l; + Top = t; + } + + #endregion Public Methods + + #region Internal Methods + + internal void DoDrawPoly(FRPaintEventArgs e) + { + Graphics g = e.Graphics; + Report report = Report; + if (report != null && report.SmoothGraphics) { - bottom += 1; + g.InterpolationMode = InterpolationMode.HighQualityBicubic; + g.SmoothingMode = SmoothingMode.AntiAlias; + } + + drawPoly(e); + + if (report != null && report.SmoothGraphics) + { + g.InterpolationMode = InterpolationMode.Default; + g.SmoothingMode = SmoothingMode.Default; } - Left += left + center.X; - center.X = -left; - base.Width = Math.Abs(right - left); - Top += top + center.Y; - center.Y = -top; - base.Height = Math.Abs(bottom - top); } - #endregion Protected Methods - #region Public Methods - /// - public override void Assign(Base source) + #endregion Internal Methods + + #region Protected Methods + + /// + /// Add point to end of polyline, need to recalculate bounds after add + /// First point must have zero coordinate and zero type. + /// Recalculate bounds. + /// Method is slow do not use this. + /// + /// local x - relative to left-top point + /// local y - relative to left-top point + /// depreceted + protected PolyPoint addPoint(float localX, float localY, byte pointType) { - base.Assign(source); + PolyPoint result; + pointsCollection.Add(result = new PolyPoint(localX, localY)); + RecalculateBounds(); + return result; + } - PolyLineObject src = source as PolyLineObject; - if (src.points == null) return; - if (src.pointTypes == null) return; - points = new List(src.points); - pointTypes = new List(src.pointTypes); - center = src.center; - //recalculateBounds(); + /// + /// Delete point from polyline by index. + /// Recalculate bounds. + /// Method is slow do not use this. + /// + /// Index of point in polyline + protected void deletePoint(int index) + { + pointsCollection.Remove(index); + RecalculateBounds(); } - /// - public override void Deserialize(FRReader reader) + /// + /// Draw polyline path to graphics + /// + /// Event arguments + protected virtual void drawPoly(FRPaintEventArgs e) { - base.Deserialize(reader); - points = new List(); - pointTypes = new List(); - string polyPoints = reader.ReadStr("PolyPoints"); - foreach (string str in polyPoints.Split('|')) - { - string[] point = str.Split('\\'); - if (point.Length == 3) - { - float f1 = float.Parse(point[0].Replace(',', '.'), CultureInfo.InvariantCulture); - float f2 = float.Parse(point[1].Replace(',', '.'), CultureInfo.InvariantCulture); - addPoint(f1, f2, byte.Parse(point[2])); - } - } - if (reader.HasProperty("CenterX")) - center.X = reader.ReadFloat("CenterX"); - if (reader.HasProperty("CenterY")) - center.Y = reader.ReadFloat("CenterY"); - //recalculateBounds(); + Pen pen; + if (polygonSelectionMode == PolygonSelectionMode.MoveAndScale) + pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); + else pen = e.Cache.GetPen(Border.Color, 1, DashStyle.Solid); + + using (GraphicsPath path = GetPath(pen, AbsLeft, AbsTop, AbsRight, AbsBottom, e.ScaleX, e.ScaleY)) + e.Graphics.DrawPath(pen, path); } - internal void DoDrawPoly(FRPaintEventArgs e) - { - Graphics g = e.Graphics; - Report report = Report; - if (report != null && report.SmoothGraphics) + /// + /// Insert point to desired place of polyline + /// recalculateBounds(); + /// Method is slow do not use this + /// + /// Index of place from zero to count + /// local x - relative to left-top point + /// local y - relative to left-top point + /// deprecated + protected PolyPoint insertPoint(int index, float localX, float localY, byte pointType) { - g.InterpolationMode = InterpolationMode.HighQualityBicubic; - g.SmoothingMode = SmoothingMode.AntiAlias; + PolyPoint result; + pointsCollection.Insert(index, result = new PolyPoint(localX, localY)); + RecalculateBounds(); + return result; } - drawPoly(e); + #endregion Protected Methods - if (report != null && report.SmoothGraphics) + #region Private Methods + + private float getDistance(float px, float py, float px0, float py0, float px1, float py1, out int index) { - g.InterpolationMode = InterpolationMode.Default; - g.SmoothingMode = SmoothingMode.Default; + float vx = px1 - px0; + float vy = py1 - py0; + float wx = px - px0; + float wy = py - py0; + float c1 = vx * wx + vy * wy; + if (c1 <= 0) { index = -1; return (px0 - px) * (px0 - px) + (py0 - py) * (py0 - py); } + float c2 = vx * vx + vy * vy; + if (c2 <= c1) { index = 1; return (px1 - px) * (px1 - px) + (py1 - py) * (py1 - py); } + float b = c1 / c2; + index = 0; + float bx = px0 + vx * b; + float by = py0 + vy * b; + return (bx - px) * (bx - px) + (by - py) * (by - py); } - } - /// - public override void Draw(FRPaintEventArgs e) + private PolyPoint GetPseudoPoint(PolyPoint start, PolyPoint end) { - if ((points == null || points.Count == 1)) + float vecX = end.X - start.X; + float vecY = end.Y - start.Y; + + float distance = (float)Math.Sqrt(vecX * vecX + vecY * vecY); + + vecX = vecX / 3; + vecY = vecY / 3; + + return new PolyPoint(start.X + vecX, start.Y + vecY); + } + + #endregion Private Methods + + #region Protected Internal Enums + + protected internal enum PolygonSelectionMode : int + { + MoveAndScale, + Normal, + AddToLine, + AddBezier, + Delete + } + + #endregion Protected Internal Enums + + #region Public Classes + + /// + /// Represent a point for polygon object + /// + public class PolyPoint + { + #region Private Fields + + private static readonly NumberFormatInfo invariant; + private PolyPoint left; + private PolyPoint right; + private float x; + private float y; + + #endregion Private Fields + + #region Public Properties + + public PolyPoint LeftCurve { - Graphics g = e.Graphics; - g.DrawLine(Pens.Black, AbsLeft * e.ScaleX - 6, AbsTop * e.ScaleY, AbsLeft * e.ScaleX + 6, AbsTop * e.ScaleY); - g.DrawLine(Pens.Black, AbsLeft * e.ScaleX, AbsTop * e.ScaleY - 6, AbsLeft * e.ScaleX, AbsTop * e.ScaleY + 6); + get { return left; } + set { left = value; } } - else + + public PolyPoint RightCurve { - DoDrawPoly(e); - DrawDesign0(e); + get { return right; } + set { right = value; } } - DrawDesign1(e); - } - /// - public override void Serialize(FRWriter writer) - { - Border.SimpleBorder = true; - base.Serialize(writer); - PolyLineObject c = writer.DiffObject as PolyLineObject; + public float X + { + get { return x; } + set { x = value; } + } - StringBuilder sb = new StringBuilder(points.Count * 10); - for (int i = 0; i < points.Count; i++) + public float Y { - sb.AppendFormat("{0}\\{1}\\{2}", points[i].X.ToString(CultureInfo.InvariantCulture), - points[i].Y.ToString(CultureInfo.InvariantCulture), - pointTypes[i]); - if (i < points.Count - 1) - sb.Append("|"); + get { return y; } + set { y = value; } } - writer.WriteStr("PolyPoints", sb.ToString()); + #endregion Public Properties - writer.WriteFloat("CenterX", center.X); - writer.WriteFloat("CenterY", center.Y); + #region Public Constructors + + static PolyPoint() + { + invariant = new NumberFormatInfo(); + invariant.NumberGroupSeparator = String.Empty; + invariant.NumberDecimalSeparator = "."; + } + + public PolyPoint() + { + } + + public PolyPoint(float x, float y) + { + this.x = x; + this.y = y; + } + + #endregion Public Constructors + + #region Public Methods + + public void Deserialize(string s) + { + string[] strs = s.Split('/'); + int index = 0; + Deserialize(strs, ref index); + if (index < strs.Length) + { + if (strs[index] == "L") + { + index++; + LeftCurve = new PolyPoint(); + LeftCurve.Deserialize(strs, ref index); + } + + if (index < strs.Length) + { + if (strs[index] == "R") + { + index++; + RightCurve = new PolyPoint(); + RightCurve.Deserialize(strs, ref index); + } + } + } + } + + public bool Near(PolyPoint p) + { + return (p != null) && (Math.Abs(x - p.x) < 0.0001) && (Math.Abs(y - p.y) < 0.0001); + } + + public void ScaleX(float scale) + { + x *= scale; + if (LeftCurve != null) + LeftCurve.X *= scale; + if (RightCurve != null) + RightCurve.X *= scale; + } + + public void ScaleY(float scale) + { + y *= scale; + if (LeftCurve != null) + LeftCurve.Y *= scale; + if (RightCurve != null) + RightCurve.Y *= scale; + } + + public void Serialize(StringBuilder sb) + { + sb.Append(Round(x)).Append("/").Append(Round(y)); + if (LeftCurve != null) + { + sb.Append("/L/").Append(Round(LeftCurve.X)).Append("/").Append(Round(LeftCurve.Y)); + } + if (RightCurve != null) + { + sb.Append("/R/").Append(Round(RightCurve.X)).Append("/").Append(Round(RightCurve.Y)); + } + } + + public override string ToString() + { + return "(" + Round(x) + ";" + Round(y) + ")"; + } + + #endregion Public Methods + + #region Private Methods + + private void Deserialize(string[] strs, ref int index) + { + for (int i = 0; i < 2 && index < strs.Length; i++) + { + switch (i) + { + case 0: + Single.TryParse(strs[index], NumberStyles.Float, invariant, out x); + break; + + case 1: + Single.TryParse(strs[index], NumberStyles.Float, invariant, out y); + break; + } + index++; + } + } + + private string Round(float value) + { + return Convert.ToString(Math.Round(value, 4), invariant); + } + + #endregion Private Methods } - public void SetPolyLine(PointF[] newPoints) + public class PolyPointCollection : IEnumerable { - if(newPoints == null || newPoints.Length == 1) + #region Private Fields + + private List points; + + #endregion Private Fields + + #region Public Indexers + + public PolyPoint this[int index] { - this.points = new List(); - this.pointTypes = new List(); + get + { + index = NormalizeIndex(index); + return points[index]; + } + set + { + index = NormalizeIndex(index); + points[index] = value; + } } - else + + #endregion Public Indexers + + #region Public Properties + + public int Count { - this.points = new List(newPoints); - byte[] pointTypes = new byte[newPoints.Length]; - if (pointTypes.Length > 0) - pointTypes[0] = 0; - for (int i = 1; i < pointTypes.Length; i++) - pointTypes[i] = 1; - this.pointTypes = new List(pointTypes); + get + { + return points.Count; + } } - recalculateBounds(); - } - #endregion Public Methods + public bool IsReadOnly + { + get + { + return false; + } + } - #region Public Constructors + #endregion Public Properties - /// - /// Initializes a new instance of the class with default settings. - /// - public PolyLineObject() - { - FlagSimpleBorder = true; - FlagUseFill = false; - points = null; - pointTypes = null; - center = PointF.Empty; - InitDesign(); + #region Public Constructors + + public PolyPointCollection() + { + points = new List(); + } + + #endregion Public Constructors + + #region Public Methods + + public void Add(PolyPoint item) + { + points.Add(item); + } + + public void Clear() + { + points.Clear(); + } + + public PolyPointCollection Clone() + { + PolyPointCollection result = new PolyPointCollection(); + result.points = new List(points); + return result; + } + + public IEnumerator GetEnumerator() + { + return points.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return points.GetEnumerator(); + } + + public int IndexOf(PolyPoint currentPoint) + { + return points.IndexOf(currentPoint); + } + + public void Insert(int index, PolyPoint item) + { + int count = points.Count; + + if (count > 0) + { + while (index < 0) + index += count; + while (index > count) + index -= count; + } + points.Insert(index, item); + } + + public void Remove(int index) + { + index = NormalizeIndex(index); + points.RemoveAt(index); + } + + #endregion Public Methods + + #region Private Methods + + private int NormalizeIndex(int index) + { + int count = points.Count; + if (count == 0) + return 0; + if (index >= 0 && index < count) + return index; + while (index < 0) + index += count; + while (index >= count) + index -= count; + return index; + } + + #endregion Private Methods } - #endregion Public Constructors + #endregion Public Classes } } \ No newline at end of file diff --git a/FastReport.Base/PolygonObject.cs b/FastReport.Base/PolygonObject.cs index 7e789f3a..bcc76083 100644 --- a/FastReport.Base/PolygonObject.cs +++ b/FastReport.Base/PolygonObject.cs @@ -41,14 +41,22 @@ protected override void drawPoly(FRPaintEventArgs e) float dx = (Width - Border.Width) * e.ScaleX - 1; float dy = (Height - Border.Width) * e.ScaleY - 1; - Pen pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); + Pen pen; + if (polygonSelectionMode == PolygonSelectionMode.MoveAndScale) + { + pen = e.Cache.GetPen(Border.Color, Border.Width * e.ScaleX, Border.DashStyle); + } + else pen = e.Cache.GetPen(Border.Color, 1, DashStyle.Solid); + Brush brush = null; if (Fill is SolidFill) brush = e.Cache.GetBrush((Fill as SolidFill).Color); else brush = Fill.CreateBrush(new RectangleF(x, y, dx, dy), e.ScaleX, e.ScaleY); + using (GraphicsPath path = getPolygonPath(pen, e.ScaleX, e.ScaleY)) { + if(polygonSelectionMode == PolygonSelectionMode.MoveAndScale) e.Graphics.FillPath(brush, path); e.Graphics.DrawPath(pen, path); } diff --git a/FastReport.Base/Report.cs b/FastReport.Base/Report.cs index a9fc27a1..aaf507df 100644 --- a/FastReport.Base/Report.cs +++ b/FastReport.Base/Report.cs @@ -804,7 +804,7 @@ internal Graphics MeasureGraphics { if (measureGraphics == null) { -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 measureBitmap = new Bitmap(1, 1); measureGraphics = Graphics.FromImage(measureBitmap); #else @@ -1266,32 +1266,9 @@ public object Calc(string expression, Variant value) DataSourceBase data = cachedItem.dataSource; Column column = cachedItem.column; - object val = column.Value; + object val = ConvertToColumnDataType(column.Value, column.DataType); - if (val == null || val is DBNull) - { - if (ConvertNulls) - val = Converter.ConvertNull(column.DataType); - } - else - { - if (val is IConvertible) - { - Type t = Nullable.GetUnderlyingType(column.DataType); - try - { - val = Convert.ChangeType(val, t != null ? t : column.DataType); - } - catch (InvalidCastException) - { - // do nothing - } - catch (FormatException) - { - // do nothing - } - } - } + if (CustomCalc != null) { @@ -1319,6 +1296,35 @@ public object Calc(string expression, Variant value) return CalcExpression(expression, value); } + private object ConvertToColumnDataType( object val, Type dataType) + { + if (val == null || val is DBNull) + { + if (ConvertNulls) + val = Converter.ConvertNull(dataType); + } + else + { + if (val is IConvertible) + { + Type t = Nullable.GetUnderlyingType(dataType); + try + { + val = Convert.ChangeType(val, t != null ? t : dataType); + } + catch (InvalidCastException) + { + // do nothing + } + catch (FormatException) + { + // do nothing + } + } + } + return val; + } + /// /// Returns an expression value. /// @@ -1381,12 +1387,7 @@ private object GetColumnValue(string complexName, bool convertNull) if (column == null) return null; - object value = column.Value; - - if (convertNull && (value == null || value is DBNull)) - value = Converter.ConvertNull(column.DataType); - - return value; + return ConvertToColumnDataType(column.Value, column.DataType); } private Variant GetTotalValue(string name, bool convertNull) diff --git a/FastReport.Base/StyleBase.cs b/FastReport.Base/StyleBase.cs index 6e082cbc..f80a9602 100644 --- a/FastReport.Base/StyleBase.cs +++ b/FastReport.Base/StyleBase.cs @@ -158,7 +158,7 @@ public virtual void Serialize(FRWriter writer) Border.Serialize(writer, "Border", c.Border); Fill.Serialize(writer, "Fill", c.Fill); TextFill.Serialize(writer, "TextFill", c.TextFill); - if (writer.SerializeTo != SerializeTo.Preview || !Font.Equals(c.Font)) + if ((writer.SerializeTo != SerializeTo.Preview || !Font.Equals(c.Font)) && writer.ItemName != "inherited") writer.WriteValue("Font", Font); if (ApplyBorder != c.ApplyBorder) writer.WriteBool("ApplyBorder", ApplyBorder); diff --git a/FastReport.Base/Table/TableResult.cs b/FastReport.Base/Table/TableResult.cs index cee19693..d9c28df3 100644 --- a/FastReport.Base/Table/TableResult.cs +++ b/FastReport.Base/Table/TableResult.cs @@ -101,7 +101,7 @@ private int GetRowsFit(int startRow, float freeSpace) while (startRow + rowsFit < Rows.Count && (rowsFit == 0 || !Rows[startRow + rowsFit].PageBreak) && - GetRowsHeight(startRow, rowsFit + 1) <= freeSpace + 0.1f) + (!this.CanBreak | GetRowsHeight(startRow, rowsFit + 1) <= freeSpace + 0.1f)) { if (keeping) { @@ -264,7 +264,7 @@ internal void CalcBounds() OnAfterData(); // calculate cells' bounds - CalcHeight(); + Height = CalcHeight(); // fire AfterCalcBounds event OnAfterCalcBounds(); @@ -325,7 +325,7 @@ private void GeneratePagesAcrossThenDown() engine.CurY = saveCurY; curY = GeneratePage(startColumn, startRow, columnsFit, rowsFit, - new RectangleF(0, 0, engine.PageWidth, freeSpace), spans) + saveCurY; + new RectangleF(0, 0, engine.PageWidth, CanBreak ? freeSpace : Height), spans) + saveCurY; Left = 0; startColumn += columnsFit; diff --git a/FastReport.Base/TextObject.cs b/FastReport.Base/TextObject.cs index 2f2dce88..6e4cbb08 100644 --- a/FastReport.Base/TextObject.cs +++ b/FastReport.Base/TextObject.cs @@ -82,7 +82,7 @@ public enum TextRenderType /// /// The format of paragraph /// - [TypeConverterAttribute(typeof(ExpandableObjectConverter))] + [TypeConverterAttribute(typeof(TypeConverters.FRExpandableObjectConverter))] public class ParagraphFormat { private float firstLineIndent; @@ -172,6 +172,26 @@ internal void Assign(ParagraphFormat p) firstLineIndent = p.firstLineIndent; skipFirstLineIndent = p.skipFirstLineIndent; } + + public override bool Equals(object obj) + { + ParagraphFormat format = obj as ParagraphFormat; + return format != null && + firstLineIndent == format.firstLineIndent && + lineSpacing == format.lineSpacing && + lineSpacingType == format.lineSpacingType && + skipFirstLineIndent == format.skipFirstLineIndent; + } + + public override int GetHashCode() + { + int hashCode = -1051315095; + hashCode = hashCode * -1521134295 + firstLineIndent.GetHashCode(); + hashCode = hashCode * -1521134295 + lineSpacing.GetHashCode(); + hashCode = hashCode * -1521134295 + lineSpacingType.GetHashCode(); + hashCode = hashCode * -1521134295 + skipFirstLineIndent.GetHashCode(); + return hashCode; + } } /// @@ -745,7 +765,7 @@ private SizeF CalcSize() return new SizeF(width, height); } } -#if !NETSTANDARD2_0 +#if !(NETSTANDARD2_0 || NETSTANDARD2_1) if (IsAdvancedRendererNeeded) #endif { @@ -763,7 +783,7 @@ private SizeF CalcSize() height += Padding.Vertical + 1; return new SizeF(width, height); } -#if !NETSTANDARD2_0 +#if !(NETSTANDARD2_0 || NETSTANDARD2_1) else { if (FontWidthRatio != 1) @@ -1278,7 +1298,7 @@ public override void Serialize(FRWriter writer) writer.WriteBool("WordWrap", WordWrap); if (Underlines != c.Underlines) writer.WriteBool("Underlines", Underlines); - if (writer.SerializeTo != SerializeTo.Preview || !Font.Equals(c.Font)) + if ((writer.SerializeTo != SerializeTo.Preview || !Font.Equals(c.Font)) && writer.ItemName != "inherited") writer.WriteValue("Font", Font); TextFill.Serialize(writer, "TextFill", c.TextFill); if (TextOutline != null) @@ -1374,7 +1394,7 @@ public override void Deserialize(FRReader reader) // skip break; default: - if (!reader.HasProperty("Font")) + if (!reader.HasProperty("Font") && reader.ItemName != "inherited") { string creatorVersion = reader.Root.GetProp("ReportInfo.CreatorVersion"); if (!String.IsNullOrEmpty(creatorVersion)) @@ -1399,8 +1419,8 @@ public override void Deserialize(FRReader reader) } break; } - } + public override void InitializeComponent() { base.InitializeComponent(); diff --git a/FastReport.Base/Utils/CompileHelper.cs b/FastReport.Base/Utils/CompileHelper.cs index 1cf41813..19539919 100644 --- a/FastReport.Base/Utils/CompileHelper.cs +++ b/FastReport.Base/Utils/CompileHelper.cs @@ -31,7 +31,7 @@ public static Assembly GenerateAssemblyInMemory(string sourceCode, params string parameters.ReferencedAssemblies.Add(asm); } -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 var mscorPath = compiler.GetReference("System.Private.CoreLib.dll").Display; parameters.ReferencedAssemblies.Add(mscorPath); diff --git a/FastReport.Base/Utils/Config.cs b/FastReport.Base/Utils/Config.cs index a5aac610..1ef196c2 100644 --- a/FastReport.Base/Utils/Config.cs +++ b/FastReport.Base/Utils/Config.cs @@ -23,6 +23,7 @@ public static partial class Config private static XmlDocument FDoc = new XmlDocument(); private static string FFolder = null; + private static string FFontListFolder = null; private static string FLogs = ""; private static ReportSettings FReportSettings = new ReportSettings(); private static bool FRightToLeft = false; @@ -84,6 +85,19 @@ public static string Folder set { FFolder = value; } } + /// + /// Gets or sets the path used to font.list file. + /// + /// + /// By default, the font.list file is saved to the FastReport.config folder + /// If WebMode enabled (or config file path is null), then file is saved in the application folder. + /// + public static string FontListFolder + { + get { return FFontListFolder; } + set { FFontListFolder = value; } + } + /// /// Gets or sets the settings for the Report component. /// @@ -165,7 +179,7 @@ internal static string GetTempFolder() internal static void Init() { -#if !NETSTANDARD2_0 +#if !(NETSTANDARD2_0 || NETSTANDARD2_1) string processName = System.Diagnostics.Process.GetCurrentProcess().ProcessName; WebMode = String.Compare(processName, "iisexpress") == 0 || String.Compare(processName, "w3wp") == 0; diff --git a/FastReport.Base/Utils/Converter.cs b/FastReport.Base/Utils/Converter.cs index 95d80274..0621c58c 100644 --- a/FastReport.Base/Utils/Converter.cs +++ b/FastReport.Base/Utils/Converter.cs @@ -13,6 +13,8 @@ namespace FastReport.Utils /// public static class Converter { + + /// /// Converts an object to a string. /// @@ -71,7 +73,13 @@ public static string ToString(object value) return type.FullName; return type.AssemblyQualifiedName; } - return TypeDescriptor.GetConverter(value).ConvertToInvariantString(value); +#if NETSTANDARD2_0 || NETSTANDARD2_1 + if (value is Font) + { + return FastReport.TypeConverters.FontConverter.Instance.ConvertToInvariantString(value); + } +#endif + return TypeDescriptor.GetConverter(value).ConvertToInvariantString(value); } /// @@ -118,6 +126,12 @@ public static object FromString(Type type, string value) value = value.Replace("\r\n", "\r"); return value.Split(new char[] { '\r' }); } +#if NETSTANDARD2_0 || NETSTANDARD2_1 + if (type == typeof(Font)) + { + return FastReport.TypeConverters.FontConverter.Instance.ConvertFromInvariantString(value); + } +#endif if (type == typeof(Color)) return new ColorConverter().ConvertFromInvariantString(value); return TypeDescriptor.GetConverter(type).ConvertFromInvariantString(value); diff --git a/FastReport.Base/Utils/DrawUtils.Win32.cs b/FastReport.Base/Utils/DrawUtils.Win32.cs index cc33b3f4..47bc4cb6 100644 --- a/FastReport.Base/Utils/DrawUtils.Win32.cs +++ b/FastReport.Base/Utils/DrawUtils.Win32.cs @@ -7,7 +7,7 @@ namespace FastReport.Utils { partial class DrawUtils { -#if NETSTANDARD2_0 +#if NETSTANDARD2_0 || NETSTANDARD2_1 static IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, DrawingOptions drawingOptions) { return IntPtr.Zero; diff --git a/FastReport.Base/Utils/FRReader.cs b/FastReport.Base/Utils/FRReader.cs index 0de22ffe..7ea6c25c 100644 --- a/FastReport.Base/Utils/FRReader.cs +++ b/FastReport.Base/Utils/FRReader.cs @@ -266,10 +266,10 @@ public IFRSerializable Read() } else { - if (!Config.WebMode) - MessageBox.Show(Res.Get("Messages,CantFindObject") + " " + curItem.Name); - else - throw new ClassException(curItem.Name); + if (!Config.WebMode) + MessageBox.Show(Res.Get("Messages,CantFindObject") + " " + curItem.Name); + else + throw new ClassException(curItem.Name); } } if (result != null) diff --git a/FastReport.Base/Utils/ImageHelper.cs b/FastReport.Base/Utils/ImageHelper.cs index 3fb444e8..e5c86c54 100644 --- a/FastReport.Base/Utils/ImageHelper.cs +++ b/FastReport.Base/Utils/ImageHelper.cs @@ -74,7 +74,13 @@ public static Image Load(byte[] bytes) { try { +#if NETSTANDARD2_0 || NETSTANDARD2_1 + // TODO memory leaks image converter + return Image.FromStream(new MemoryStream(bytes)); +#else return new ImageConverter().ConvertFrom(bytes) as Image; +#endif + } catch { diff --git a/FastReport.Base/Utils/MyEncodingInfo.cs b/FastReport.Base/Utils/MyEncodingInfo.cs new file mode 100644 index 00000000..a52aa0fb --- /dev/null +++ b/FastReport.Base/Utils/MyEncodingInfo.cs @@ -0,0 +1,109 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace FastReport.Utils +{ + internal class MyEncodingInfo + { + #region Private Fields + + private int codePage; + private string displayName; + private string name; + + #endregion Private Fields + + #region Public Properties + + public int CodePage + { + get + { + return codePage; + } + set + { + codePage = value; + } + } + + public string DisplayName + { + get { return displayName; } + set + { + displayName = value; + } + } + + public string Name + { + get + { + return name; + } + + set + { + name = value; + } + } + + #endregion Public Properties + + #region Public Constructors + + public MyEncodingInfo(Encoding encoding) + { + DisplayName = encoding.EncodingName; + Name = encoding.WebName; + CodePage = encoding.CodePage; + } + + public MyEncodingInfo(EncodingInfo info) + { + DisplayName = info.DisplayName; + Name = info.Name; + CodePage = info.CodePage; + } + + #endregion Public Constructors + + #region Public Methods + + public static IEnumerable GetEncodings() + { + List encodings = new List(); + + foreach (EncodingInfo info in Encoding.GetEncodings()) + { + encodings.Add(new MyEncodingInfo(info)); + } + + encodings.Sort(new Comparison(compareEncoding)); ; + + return encodings; + } + + public override string ToString() + { + return DisplayName; + } + + #endregion Public Methods + + #region Private Methods + + private static int compareEncoding(MyEncodingInfo x, MyEncodingInfo y) + { + if (x != null && y != null) + { + return String.Compare(x.DisplayName, y.DisplayName); + } + return 0; + } + + #endregion Private Methods + } +} \ No newline at end of file diff --git a/FastReport.Base/Utils/Res.cs b/FastReport.Base/Utils/Res.cs index 422b42e9..6845f360 100644 --- a/FastReport.Base/Utils/Res.cs +++ b/FastReport.Base/Utils/Res.cs @@ -35,7 +35,7 @@ public static string LocaleFolder Report.EnsureInit(); string folder = Config.Root.FindItem("Language").GetProp("Folder"); // check the registry -#if !NETSTANDARD2_0 +#if !(NETSTANDARD2_0 || NETSTANDARD2_1) if (String.IsNullOrEmpty(folder) && !Config.WebMode) { RegistryKey key = Registry.CurrentUser.OpenSubKey("Software").OpenSubKey("FastReports"); @@ -47,8 +47,8 @@ public static string LocaleFolder } } #endif - // get application folder - if (String.IsNullOrEmpty(folder)) + // get application folder + if (String.IsNullOrEmpty(folder)) folder = Config.ApplicationFolder; if (!folder.EndsWith("\\")) diff --git a/FastReport.Base/Utils/Xml.cs b/FastReport.Base/Utils/Xml.cs index 91962761..4489cf5f 100644 --- a/FastReport.Base/Utils/Xml.cs +++ b/FastReport.Base/Utils/Xml.cs @@ -6,8 +6,7 @@ namespace FastReport.Utils { /// - /// Represents a xml property. - /// + /// Represents a xml property./// public struct XmlProperty { private readonly string key; diff --git a/FastReport.Base/Watermark.cs b/FastReport.Base/Watermark.cs index 3023a438..93eab206 100644 --- a/FastReport.Base/Watermark.cs +++ b/FastReport.Base/Watermark.cs @@ -296,7 +296,7 @@ public void Serialize(FRWriter writer, string prefix, Watermark c) writer.WriteFloat(prefix + ".ImageTransparency", ImageTransparency); if (Text != c.Text) writer.WriteStr(prefix + ".Text", Text); - if (writer.SerializeTo != SerializeTo.Preview || !writer.AreEqual(Font, c.Font)) + if ((writer.SerializeTo != SerializeTo.Preview || !writer.AreEqual(Font, c.Font)) && writer.ItemName != "inherited") writer.WriteValue(prefix + ".Font", Font); TextFill.Serialize(writer, prefix + ".TextFill", c.TextFill); if (TextRotation != c.TextRotation) diff --git a/FastReport.Core.Web/Application/WebReportDesigner.cs b/FastReport.Core.Web/Application/WebReportDesigner.cs index 5d048755..5b1a715e 100644 --- a/FastReport.Core.Web/Application/WebReportDesigner.cs +++ b/FastReport.Core.Web/Application/WebReportDesigner.cs @@ -102,7 +102,9 @@ internal IActionResult DesignerSaveReport(HttpContext context) if (!DesignerSaveCallBack.IsNullOrWhiteSpace()) { string report = Report.SaveToString(); - string reportFileName = $"{ID}.frx"; + var reportName = (!String.IsNullOrEmpty(Report.ReportInfo.Name) ? + Report.ReportInfo.Name : Path.GetFileNameWithoutExtension(Report.FileName)); + string reportFileName = $"{reportName}.frx"; UriBuilder uri = new UriBuilder { diff --git a/FastReport.OpenSource/DotNetClasses/CSharpCodeProvider.cs b/FastReport.OpenSource/DotNetClasses/CSharpCodeProvider.cs index a6c6d7f0..a6196dd7 100644 --- a/FastReport.OpenSource/DotNetClasses/CSharpCodeProvider.cs +++ b/FastReport.OpenSource/DotNetClasses/CSharpCodeProvider.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using System; @@ -79,4 +80,5 @@ public override void Dispose() } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/CodeDomProvider.cs b/FastReport.OpenSource/DotNetClasses/CodeDomProvider.cs index f06dcbdc..450006d0 100644 --- a/FastReport.OpenSource/DotNetClasses/CodeDomProvider.cs +++ b/FastReport.OpenSource/DotNetClasses/CodeDomProvider.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using Microsoft.CodeAnalysis; using System; using System.Collections.Generic; using System.Reflection; @@ -19,7 +20,7 @@ protected void AddExtraAssemblies(Collections.Specialized.StringCollection refer "netstandard", "System.Runtime", "System.ComponentModel.Primitives", - "CoreCompat.System.Drawing" + "System.Drawing.Common" }; foreach(string assembly in assemblies) @@ -66,4 +67,5 @@ internal MetadataReference GetReference(string refDll) } } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/CodeGenerator.cs b/FastReport.OpenSource/DotNetClasses/CodeGenerator.cs index 7ab151dc..32ef525f 100644 --- a/FastReport.OpenSource/DotNetClasses/CodeGenerator.cs +++ b/FastReport.OpenSource/DotNetClasses/CodeGenerator.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections.Generic; using System.Text; @@ -13,3 +14,4 @@ internal static bool IsValidLanguageIndependentIdentifier(string value) } } } +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/Color.Core.cs b/FastReport.OpenSource/DotNetClasses/Color.Core.cs index f59f8be6..5b54a878 100644 --- a/FastReport.OpenSource/DotNetClasses/Color.Core.cs +++ b/FastReport.OpenSource/DotNetClasses/Color.Core.cs @@ -1,27 +1,564 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Text; namespace System.Drawing { + #if NETSTANDARD2_0 + public enum KnownColor + { + ActiveBorder = 1, + ActiveCaption = 2, + ActiveCaptionText = 3, + AppWorkspace = 4, + Control = 5, + ControlDark = 6, + ControlDarkDark = 7, + ControlLight = 8, + ControlLightLight = 9, + ControlText = 10, + Desktop = 11, + GrayText = 12, + Highlight = 13, + HighlightText = 14, + HotTrack = 15, + InactiveBorder = 16, + InactiveCaption = 17, + InactiveCaptionText = 18, + Info = 19, + InfoText = 20, + Menu = 21, + MenuText = 22, + ScrollBar = 23, + Window = 24, + WindowFrame = 25, + WindowText = 26, + Transparent = 27, + AliceBlue = 28, + AntiqueWhite = 29, + Aqua = 30, + Aquamarine = 31, + Azure = 32, + Beige = 33, + Bisque = 34, + Black = 35, + BlanchedAlmond = 36, + Blue = 37, + BlueViolet = 38, + Brown = 39, + BurlyWood = 40, + CadetBlue = 41, + Chartreuse = 42, + Chocolate = 43, + Coral = 44, + CornflowerBlue = 45, + Cornsilk = 46, + Crimson = 47, + Cyan = 48, + DarkBlue = 49, + DarkCyan = 50, + DarkGoldenrod = 51, + DarkGray = 52, + DarkGreen = 53, + DarkKhaki = 54, + DarkMagenta = 55, + DarkOliveGreen = 56, + DarkOrange = 57, + DarkOrchid = 58, + DarkRed = 59, + DarkSalmon = 60, + DarkSeaGreen = 61, + DarkSlateBlue = 62, + DarkSlateGray = 63, + DarkTurquoise = 64, + DarkViolet = 65, + DeepPink = 66, + DeepSkyBlue = 67, + DimGray = 68, + DodgerBlue = 69, + Firebrick = 70, + FloralWhite = 71, + ForestGreen = 72, + Fuchsia = 73, + Gainsboro = 74, + GhostWhite = 75, + Gold = 76, + Goldenrod = 77, + Gray = 78, + Green = 79, + GreenYellow = 80, + Honeydew = 81, + HotPink = 82, + IndianRed = 83, + Indigo = 84, + Ivory = 85, + Khaki = 86, + Lavender = 87, + LavenderBlush = 88, + LawnGreen = 89, + LemonChiffon = 90, + LightBlue = 91, + LightCoral = 92, + LightCyan = 93, + LightGoldenrodYellow = 94, + LightGray = 95, + LightGreen = 96, + LightPink = 97, + LightSalmon = 98, + LightSeaGreen = 99, + LightSkyBlue = 100, + LightSlateGray = 101, + LightSteelBlue = 102, + LightYellow = 103, + Lime = 104, + LimeGreen = 105, + Linen = 106, + Magenta = 107, + Maroon = 108, + MediumAquamarine = 109, + MediumBlue = 110, + MediumOrchid = 111, + MediumPurple = 112, + MediumSeaGreen = 113, + MediumSlateBlue = 114, + MediumSpringGreen = 115, + MediumTurquoise = 116, + MediumVioletRed = 117, + MidnightBlue = 118, + MintCream = 119, + MistyRose = 120, + Moccasin = 121, + NavajoWhite = 122, + Navy = 123, + OldLace = 124, + Olive = 125, + OliveDrab = 126, + Orange = 127, + OrangeRed = 128, + Orchid = 129, + PaleGoldenrod = 130, + PaleGreen = 131, + PaleTurquoise = 132, + PaleVioletRed = 133, + PapayaWhip = 134, + PeachPuff = 135, + Peru = 136, + Pink = 137, + Plum = 138, + PowderBlue = 139, + Purple = 140, + Red = 141, + RosyBrown = 142, + RoyalBlue = 143, + SaddleBrown = 144, + Salmon = 145, + SandyBrown = 146, + SeaGreen = 147, + SeaShell = 148, + Sienna = 149, + Silver = 150, + SkyBlue = 151, + SlateBlue = 152, + SlateGray = 153, + Snow = 154, + SpringGreen = 155, + SteelBlue = 156, + Tan = 157, + Teal = 158, + Thistle = 159, + Tomato = 160, + Turquoise = 161, + Violet = 162, + Wheat = 163, + White = 164, + WhiteSmoke = 165, + Yellow = 166, + YellowGreen = 167, + ButtonFace = 168, + ButtonHighlight = 169, + ButtonShadow = 170, + GradientActiveCaption = 171, + GradientInactiveCaption = 172, + MenuBar = 173, + MenuHighlight = 174 + } +#endif public class ColorExt { + private static readonly ConcurrentDictionary ColorToKnownColor = new ConcurrentDictionary(); + private static readonly ConcurrentDictionary KnownColorToColor = new ConcurrentDictionary(); + + static ColorExt() + { + ColorToKnownColor[-4934476] = KnownColor.ActiveBorder; + KnownColorToColor[KnownColor.ActiveBorder] = Color.FromArgb(-4934476); + ColorToKnownColor[-6703919] = KnownColor.ActiveCaption; + KnownColorToColor[KnownColor.ActiveCaption] = Color.FromArgb(-6703919); + ColorToKnownColor[-16777216] = KnownColor.ActiveCaptionText; + KnownColorToColor[KnownColor.ActiveCaptionText] = Color.FromArgb(-16777216); + ColorToKnownColor[-5526613] = KnownColor.AppWorkspace; + KnownColorToColor[KnownColor.AppWorkspace] = Color.FromArgb(-5526613); + ColorToKnownColor[-986896] = KnownColor.Control; + KnownColorToColor[KnownColor.Control] = Color.FromArgb(-986896); + ColorToKnownColor[-6250336] = KnownColor.ControlDark; + KnownColorToColor[KnownColor.ControlDark] = Color.FromArgb(-6250336); + ColorToKnownColor[-9868951] = KnownColor.ControlDarkDark; + KnownColorToColor[KnownColor.ControlDarkDark] = Color.FromArgb(-9868951); + ColorToKnownColor[-1842205] = KnownColor.ControlLight; + KnownColorToColor[KnownColor.ControlLight] = Color.FromArgb(-1842205); + ColorToKnownColor[-1] = KnownColor.ControlLightLight; + KnownColorToColor[KnownColor.ControlLightLight] = Color.FromArgb(-1); + ColorToKnownColor[-16777216] = KnownColor.ControlText; + KnownColorToColor[KnownColor.ControlText] = Color.FromArgb(-16777216); + ColorToKnownColor[-16777216] = KnownColor.Desktop; + KnownColorToColor[KnownColor.Desktop] = Color.FromArgb(-16777216); + ColorToKnownColor[-9605779] = KnownColor.GrayText; + KnownColorToColor[KnownColor.GrayText] = Color.FromArgb(-9605779); + ColorToKnownColor[-16746281] = KnownColor.Highlight; + KnownColorToColor[KnownColor.Highlight] = Color.FromArgb(-16746281); + ColorToKnownColor[-1] = KnownColor.HighlightText; + KnownColorToColor[KnownColor.HighlightText] = Color.FromArgb(-1); + ColorToKnownColor[-16750900] = KnownColor.HotTrack; + KnownColorToColor[KnownColor.HotTrack] = Color.FromArgb(-16750900); + ColorToKnownColor[-722948] = KnownColor.InactiveBorder; + KnownColorToColor[KnownColor.InactiveBorder] = Color.FromArgb(-722948); + ColorToKnownColor[-4207141] = KnownColor.InactiveCaption; + KnownColorToColor[KnownColor.InactiveCaption] = Color.FromArgb(-4207141); + ColorToKnownColor[-16777216] = KnownColor.InactiveCaptionText; + KnownColorToColor[KnownColor.InactiveCaptionText] = Color.FromArgb(-16777216); + ColorToKnownColor[-31] = KnownColor.Info; + KnownColorToColor[KnownColor.Info] = Color.FromArgb(-31); + ColorToKnownColor[-16777216] = KnownColor.InfoText; + KnownColorToColor[KnownColor.InfoText] = Color.FromArgb(-16777216); + ColorToKnownColor[-986896] = KnownColor.Menu; + KnownColorToColor[KnownColor.Menu] = Color.FromArgb(-986896); + ColorToKnownColor[-16777216] = KnownColor.MenuText; + KnownColorToColor[KnownColor.MenuText] = Color.FromArgb(-16777216); + ColorToKnownColor[-3618616] = KnownColor.ScrollBar; + KnownColorToColor[KnownColor.ScrollBar] = Color.FromArgb(-3618616); + ColorToKnownColor[-1] = KnownColor.Window; + KnownColorToColor[KnownColor.Window] = Color.FromArgb(-1); + ColorToKnownColor[-10197916] = KnownColor.WindowFrame; + KnownColorToColor[KnownColor.WindowFrame] = Color.FromArgb(-10197916); + ColorToKnownColor[-16777216] = KnownColor.WindowText; + KnownColorToColor[KnownColor.WindowText] = Color.FromArgb(-16777216); + ColorToKnownColor[16777215] = KnownColor.Transparent; + KnownColorToColor[KnownColor.Transparent] = Color.FromArgb(16777215); + ColorToKnownColor[-984833] = KnownColor.AliceBlue; + KnownColorToColor[KnownColor.AliceBlue] = Color.FromArgb(-984833); + ColorToKnownColor[-332841] = KnownColor.AntiqueWhite; + KnownColorToColor[KnownColor.AntiqueWhite] = Color.FromArgb(-332841); + ColorToKnownColor[-16711681] = KnownColor.Aqua; + KnownColorToColor[KnownColor.Aqua] = Color.FromArgb(-16711681); + ColorToKnownColor[-8388652] = KnownColor.Aquamarine; + KnownColorToColor[KnownColor.Aquamarine] = Color.FromArgb(-8388652); + ColorToKnownColor[-983041] = KnownColor.Azure; + KnownColorToColor[KnownColor.Azure] = Color.FromArgb(-983041); + ColorToKnownColor[-657956] = KnownColor.Beige; + KnownColorToColor[KnownColor.Beige] = Color.FromArgb(-657956); + ColorToKnownColor[-6972] = KnownColor.Bisque; + KnownColorToColor[KnownColor.Bisque] = Color.FromArgb(-6972); + ColorToKnownColor[-16777216] = KnownColor.Black; + KnownColorToColor[KnownColor.Black] = Color.FromArgb(-16777216); + ColorToKnownColor[-5171] = KnownColor.BlanchedAlmond; + KnownColorToColor[KnownColor.BlanchedAlmond] = Color.FromArgb(-5171); + ColorToKnownColor[-16776961] = KnownColor.Blue; + KnownColorToColor[KnownColor.Blue] = Color.FromArgb(-16776961); + ColorToKnownColor[-7722014] = KnownColor.BlueViolet; + KnownColorToColor[KnownColor.BlueViolet] = Color.FromArgb(-7722014); + ColorToKnownColor[-5952982] = KnownColor.Brown; + KnownColorToColor[KnownColor.Brown] = Color.FromArgb(-5952982); + ColorToKnownColor[-2180985] = KnownColor.BurlyWood; + KnownColorToColor[KnownColor.BurlyWood] = Color.FromArgb(-2180985); + ColorToKnownColor[-10510688] = KnownColor.CadetBlue; + KnownColorToColor[KnownColor.CadetBlue] = Color.FromArgb(-10510688); + ColorToKnownColor[-8388864] = KnownColor.Chartreuse; + KnownColorToColor[KnownColor.Chartreuse] = Color.FromArgb(-8388864); + ColorToKnownColor[-2987746] = KnownColor.Chocolate; + KnownColorToColor[KnownColor.Chocolate] = Color.FromArgb(-2987746); + ColorToKnownColor[-32944] = KnownColor.Coral; + KnownColorToColor[KnownColor.Coral] = Color.FromArgb(-32944); + ColorToKnownColor[-10185235] = KnownColor.CornflowerBlue; + KnownColorToColor[KnownColor.CornflowerBlue] = Color.FromArgb(-10185235); + ColorToKnownColor[-1828] = KnownColor.Cornsilk; + KnownColorToColor[KnownColor.Cornsilk] = Color.FromArgb(-1828); + ColorToKnownColor[-2354116] = KnownColor.Crimson; + KnownColorToColor[KnownColor.Crimson] = Color.FromArgb(-2354116); + ColorToKnownColor[-16711681] = KnownColor.Cyan; + KnownColorToColor[KnownColor.Cyan] = Color.FromArgb(-16711681); + ColorToKnownColor[-16777077] = KnownColor.DarkBlue; + KnownColorToColor[KnownColor.DarkBlue] = Color.FromArgb(-16777077); + ColorToKnownColor[-16741493] = KnownColor.DarkCyan; + KnownColorToColor[KnownColor.DarkCyan] = Color.FromArgb(-16741493); + ColorToKnownColor[-4684277] = KnownColor.DarkGoldenrod; + KnownColorToColor[KnownColor.DarkGoldenrod] = Color.FromArgb(-4684277); + ColorToKnownColor[-5658199] = KnownColor.DarkGray; + KnownColorToColor[KnownColor.DarkGray] = Color.FromArgb(-5658199); + ColorToKnownColor[-16751616] = KnownColor.DarkGreen; + KnownColorToColor[KnownColor.DarkGreen] = Color.FromArgb(-16751616); + ColorToKnownColor[-4343957] = KnownColor.DarkKhaki; + KnownColorToColor[KnownColor.DarkKhaki] = Color.FromArgb(-4343957); + ColorToKnownColor[-7667573] = KnownColor.DarkMagenta; + KnownColorToColor[KnownColor.DarkMagenta] = Color.FromArgb(-7667573); + ColorToKnownColor[-11179217] = KnownColor.DarkOliveGreen; + KnownColorToColor[KnownColor.DarkOliveGreen] = Color.FromArgb(-11179217); + ColorToKnownColor[-29696] = KnownColor.DarkOrange; + KnownColorToColor[KnownColor.DarkOrange] = Color.FromArgb(-29696); + ColorToKnownColor[-6737204] = KnownColor.DarkOrchid; + KnownColorToColor[KnownColor.DarkOrchid] = Color.FromArgb(-6737204); + ColorToKnownColor[-7667712] = KnownColor.DarkRed; + KnownColorToColor[KnownColor.DarkRed] = Color.FromArgb(-7667712); + ColorToKnownColor[-1468806] = KnownColor.DarkSalmon; + KnownColorToColor[KnownColor.DarkSalmon] = Color.FromArgb(-1468806); + ColorToKnownColor[-7357301] = KnownColor.DarkSeaGreen; + KnownColorToColor[KnownColor.DarkSeaGreen] = Color.FromArgb(-7357301); + ColorToKnownColor[-12042869] = KnownColor.DarkSlateBlue; + KnownColorToColor[KnownColor.DarkSlateBlue] = Color.FromArgb(-12042869); + ColorToKnownColor[-13676721] = KnownColor.DarkSlateGray; + KnownColorToColor[KnownColor.DarkSlateGray] = Color.FromArgb(-13676721); + ColorToKnownColor[-16724271] = KnownColor.DarkTurquoise; + KnownColorToColor[KnownColor.DarkTurquoise] = Color.FromArgb(-16724271); + ColorToKnownColor[-7077677] = KnownColor.DarkViolet; + KnownColorToColor[KnownColor.DarkViolet] = Color.FromArgb(-7077677); + ColorToKnownColor[-60269] = KnownColor.DeepPink; + KnownColorToColor[KnownColor.DeepPink] = Color.FromArgb(-60269); + ColorToKnownColor[-16728065] = KnownColor.DeepSkyBlue; + KnownColorToColor[KnownColor.DeepSkyBlue] = Color.FromArgb(-16728065); + ColorToKnownColor[-9868951] = KnownColor.DimGray; + KnownColorToColor[KnownColor.DimGray] = Color.FromArgb(-9868951); + ColorToKnownColor[-14774017] = KnownColor.DodgerBlue; + KnownColorToColor[KnownColor.DodgerBlue] = Color.FromArgb(-14774017); + ColorToKnownColor[-5103070] = KnownColor.Firebrick; + KnownColorToColor[KnownColor.Firebrick] = Color.FromArgb(-5103070); + ColorToKnownColor[-1296] = KnownColor.FloralWhite; + KnownColorToColor[KnownColor.FloralWhite] = Color.FromArgb(-1296); + ColorToKnownColor[-14513374] = KnownColor.ForestGreen; + KnownColorToColor[KnownColor.ForestGreen] = Color.FromArgb(-14513374); + ColorToKnownColor[-65281] = KnownColor.Fuchsia; + KnownColorToColor[KnownColor.Fuchsia] = Color.FromArgb(-65281); + ColorToKnownColor[-2302756] = KnownColor.Gainsboro; + KnownColorToColor[KnownColor.Gainsboro] = Color.FromArgb(-2302756); + ColorToKnownColor[-460545] = KnownColor.GhostWhite; + KnownColorToColor[KnownColor.GhostWhite] = Color.FromArgb(-460545); + ColorToKnownColor[-10496] = KnownColor.Gold; + KnownColorToColor[KnownColor.Gold] = Color.FromArgb(-10496); + ColorToKnownColor[-2448096] = KnownColor.Goldenrod; + KnownColorToColor[KnownColor.Goldenrod] = Color.FromArgb(-2448096); + ColorToKnownColor[-8355712] = KnownColor.Gray; + KnownColorToColor[KnownColor.Gray] = Color.FromArgb(-8355712); + ColorToKnownColor[-16744448] = KnownColor.Green; + KnownColorToColor[KnownColor.Green] = Color.FromArgb(-16744448); + ColorToKnownColor[-5374161] = KnownColor.GreenYellow; + KnownColorToColor[KnownColor.GreenYellow] = Color.FromArgb(-5374161); + ColorToKnownColor[-983056] = KnownColor.Honeydew; + KnownColorToColor[KnownColor.Honeydew] = Color.FromArgb(-983056); + ColorToKnownColor[-38476] = KnownColor.HotPink; + KnownColorToColor[KnownColor.HotPink] = Color.FromArgb(-38476); + ColorToKnownColor[-3318692] = KnownColor.IndianRed; + KnownColorToColor[KnownColor.IndianRed] = Color.FromArgb(-3318692); + ColorToKnownColor[-11861886] = KnownColor.Indigo; + KnownColorToColor[KnownColor.Indigo] = Color.FromArgb(-11861886); + ColorToKnownColor[-16] = KnownColor.Ivory; + KnownColorToColor[KnownColor.Ivory] = Color.FromArgb(-16); + ColorToKnownColor[-989556] = KnownColor.Khaki; + KnownColorToColor[KnownColor.Khaki] = Color.FromArgb(-989556); + ColorToKnownColor[-1644806] = KnownColor.Lavender; + KnownColorToColor[KnownColor.Lavender] = Color.FromArgb(-1644806); + ColorToKnownColor[-3851] = KnownColor.LavenderBlush; + KnownColorToColor[KnownColor.LavenderBlush] = Color.FromArgb(-3851); + ColorToKnownColor[-8586240] = KnownColor.LawnGreen; + KnownColorToColor[KnownColor.LawnGreen] = Color.FromArgb(-8586240); + ColorToKnownColor[-1331] = KnownColor.LemonChiffon; + KnownColorToColor[KnownColor.LemonChiffon] = Color.FromArgb(-1331); + ColorToKnownColor[-5383962] = KnownColor.LightBlue; + KnownColorToColor[KnownColor.LightBlue] = Color.FromArgb(-5383962); + ColorToKnownColor[-1015680] = KnownColor.LightCoral; + KnownColorToColor[KnownColor.LightCoral] = Color.FromArgb(-1015680); + ColorToKnownColor[-2031617] = KnownColor.LightCyan; + KnownColorToColor[KnownColor.LightCyan] = Color.FromArgb(-2031617); + ColorToKnownColor[-329006] = KnownColor.LightGoldenrodYellow; + KnownColorToColor[KnownColor.LightGoldenrodYellow] = Color.FromArgb(-329006); + ColorToKnownColor[-2894893] = KnownColor.LightGray; + KnownColorToColor[KnownColor.LightGray] = Color.FromArgb(-2894893); + ColorToKnownColor[-7278960] = KnownColor.LightGreen; + KnownColorToColor[KnownColor.LightGreen] = Color.FromArgb(-7278960); + ColorToKnownColor[-18751] = KnownColor.LightPink; + KnownColorToColor[KnownColor.LightPink] = Color.FromArgb(-18751); + ColorToKnownColor[-24454] = KnownColor.LightSalmon; + KnownColorToColor[KnownColor.LightSalmon] = Color.FromArgb(-24454); + ColorToKnownColor[-14634326] = KnownColor.LightSeaGreen; + KnownColorToColor[KnownColor.LightSeaGreen] = Color.FromArgb(-14634326); + ColorToKnownColor[-7876870] = KnownColor.LightSkyBlue; + KnownColorToColor[KnownColor.LightSkyBlue] = Color.FromArgb(-7876870); + ColorToKnownColor[-8943463] = KnownColor.LightSlateGray; + KnownColorToColor[KnownColor.LightSlateGray] = Color.FromArgb(-8943463); + ColorToKnownColor[-5192482] = KnownColor.LightSteelBlue; + KnownColorToColor[KnownColor.LightSteelBlue] = Color.FromArgb(-5192482); + ColorToKnownColor[-32] = KnownColor.LightYellow; + KnownColorToColor[KnownColor.LightYellow] = Color.FromArgb(-32); + ColorToKnownColor[-16711936] = KnownColor.Lime; + KnownColorToColor[KnownColor.Lime] = Color.FromArgb(-16711936); + ColorToKnownColor[-13447886] = KnownColor.LimeGreen; + KnownColorToColor[KnownColor.LimeGreen] = Color.FromArgb(-13447886); + ColorToKnownColor[-331546] = KnownColor.Linen; + KnownColorToColor[KnownColor.Linen] = Color.FromArgb(-331546); + ColorToKnownColor[-65281] = KnownColor.Magenta; + KnownColorToColor[KnownColor.Magenta] = Color.FromArgb(-65281); + ColorToKnownColor[-8388608] = KnownColor.Maroon; + KnownColorToColor[KnownColor.Maroon] = Color.FromArgb(-8388608); + ColorToKnownColor[-10039894] = KnownColor.MediumAquamarine; + KnownColorToColor[KnownColor.MediumAquamarine] = Color.FromArgb(-10039894); + ColorToKnownColor[-16777011] = KnownColor.MediumBlue; + KnownColorToColor[KnownColor.MediumBlue] = Color.FromArgb(-16777011); + ColorToKnownColor[-4565549] = KnownColor.MediumOrchid; + KnownColorToColor[KnownColor.MediumOrchid] = Color.FromArgb(-4565549); + ColorToKnownColor[-7114533] = KnownColor.MediumPurple; + KnownColorToColor[KnownColor.MediumPurple] = Color.FromArgb(-7114533); + ColorToKnownColor[-12799119] = KnownColor.MediumSeaGreen; + KnownColorToColor[KnownColor.MediumSeaGreen] = Color.FromArgb(-12799119); + ColorToKnownColor[-8689426] = KnownColor.MediumSlateBlue; + KnownColorToColor[KnownColor.MediumSlateBlue] = Color.FromArgb(-8689426); + ColorToKnownColor[-16713062] = KnownColor.MediumSpringGreen; + KnownColorToColor[KnownColor.MediumSpringGreen] = Color.FromArgb(-16713062); + ColorToKnownColor[-12004916] = KnownColor.MediumTurquoise; + KnownColorToColor[KnownColor.MediumTurquoise] = Color.FromArgb(-12004916); + ColorToKnownColor[-3730043] = KnownColor.MediumVioletRed; + KnownColorToColor[KnownColor.MediumVioletRed] = Color.FromArgb(-3730043); + ColorToKnownColor[-15132304] = KnownColor.MidnightBlue; + KnownColorToColor[KnownColor.MidnightBlue] = Color.FromArgb(-15132304); + ColorToKnownColor[-655366] = KnownColor.MintCream; + KnownColorToColor[KnownColor.MintCream] = Color.FromArgb(-655366); + ColorToKnownColor[-6943] = KnownColor.MistyRose; + KnownColorToColor[KnownColor.MistyRose] = Color.FromArgb(-6943); + ColorToKnownColor[-6987] = KnownColor.Moccasin; + KnownColorToColor[KnownColor.Moccasin] = Color.FromArgb(-6987); + ColorToKnownColor[-8531] = KnownColor.NavajoWhite; + KnownColorToColor[KnownColor.NavajoWhite] = Color.FromArgb(-8531); + ColorToKnownColor[-16777088] = KnownColor.Navy; + KnownColorToColor[KnownColor.Navy] = Color.FromArgb(-16777088); + ColorToKnownColor[-133658] = KnownColor.OldLace; + KnownColorToColor[KnownColor.OldLace] = Color.FromArgb(-133658); + ColorToKnownColor[-8355840] = KnownColor.Olive; + KnownColorToColor[KnownColor.Olive] = Color.FromArgb(-8355840); + ColorToKnownColor[-9728477] = KnownColor.OliveDrab; + KnownColorToColor[KnownColor.OliveDrab] = Color.FromArgb(-9728477); + ColorToKnownColor[-23296] = KnownColor.Orange; + KnownColorToColor[KnownColor.Orange] = Color.FromArgb(-23296); + ColorToKnownColor[-47872] = KnownColor.OrangeRed; + KnownColorToColor[KnownColor.OrangeRed] = Color.FromArgb(-47872); + ColorToKnownColor[-2461482] = KnownColor.Orchid; + KnownColorToColor[KnownColor.Orchid] = Color.FromArgb(-2461482); + ColorToKnownColor[-1120086] = KnownColor.PaleGoldenrod; + KnownColorToColor[KnownColor.PaleGoldenrod] = Color.FromArgb(-1120086); + ColorToKnownColor[-6751336] = KnownColor.PaleGreen; + KnownColorToColor[KnownColor.PaleGreen] = Color.FromArgb(-6751336); + ColorToKnownColor[-5247250] = KnownColor.PaleTurquoise; + KnownColorToColor[KnownColor.PaleTurquoise] = Color.FromArgb(-5247250); + ColorToKnownColor[-2396013] = KnownColor.PaleVioletRed; + KnownColorToColor[KnownColor.PaleVioletRed] = Color.FromArgb(-2396013); + ColorToKnownColor[-4139] = KnownColor.PapayaWhip; + KnownColorToColor[KnownColor.PapayaWhip] = Color.FromArgb(-4139); + ColorToKnownColor[-9543] = KnownColor.PeachPuff; + KnownColorToColor[KnownColor.PeachPuff] = Color.FromArgb(-9543); + ColorToKnownColor[-3308225] = KnownColor.Peru; + KnownColorToColor[KnownColor.Peru] = Color.FromArgb(-3308225); + ColorToKnownColor[-16181] = KnownColor.Pink; + KnownColorToColor[KnownColor.Pink] = Color.FromArgb(-16181); + ColorToKnownColor[-2252579] = KnownColor.Plum; + KnownColorToColor[KnownColor.Plum] = Color.FromArgb(-2252579); + ColorToKnownColor[-5185306] = KnownColor.PowderBlue; + KnownColorToColor[KnownColor.PowderBlue] = Color.FromArgb(-5185306); + ColorToKnownColor[-8388480] = KnownColor.Purple; + KnownColorToColor[KnownColor.Purple] = Color.FromArgb(-8388480); + ColorToKnownColor[-65536] = KnownColor.Red; + KnownColorToColor[KnownColor.Red] = Color.FromArgb(-65536); + ColorToKnownColor[-4419697] = KnownColor.RosyBrown; + KnownColorToColor[KnownColor.RosyBrown] = Color.FromArgb(-4419697); + ColorToKnownColor[-12490271] = KnownColor.RoyalBlue; + KnownColorToColor[KnownColor.RoyalBlue] = Color.FromArgb(-12490271); + ColorToKnownColor[-7650029] = KnownColor.SaddleBrown; + KnownColorToColor[KnownColor.SaddleBrown] = Color.FromArgb(-7650029); + ColorToKnownColor[-360334] = KnownColor.Salmon; + KnownColorToColor[KnownColor.Salmon] = Color.FromArgb(-360334); + ColorToKnownColor[-744352] = KnownColor.SandyBrown; + KnownColorToColor[KnownColor.SandyBrown] = Color.FromArgb(-744352); + ColorToKnownColor[-13726889] = KnownColor.SeaGreen; + KnownColorToColor[KnownColor.SeaGreen] = Color.FromArgb(-13726889); + ColorToKnownColor[-2578] = KnownColor.SeaShell; + KnownColorToColor[KnownColor.SeaShell] = Color.FromArgb(-2578); + ColorToKnownColor[-6270419] = KnownColor.Sienna; + KnownColorToColor[KnownColor.Sienna] = Color.FromArgb(-6270419); + ColorToKnownColor[-4144960] = KnownColor.Silver; + KnownColorToColor[KnownColor.Silver] = Color.FromArgb(-4144960); + ColorToKnownColor[-7876885] = KnownColor.SkyBlue; + KnownColorToColor[KnownColor.SkyBlue] = Color.FromArgb(-7876885); + ColorToKnownColor[-9807155] = KnownColor.SlateBlue; + KnownColorToColor[KnownColor.SlateBlue] = Color.FromArgb(-9807155); + ColorToKnownColor[-9404272] = KnownColor.SlateGray; + KnownColorToColor[KnownColor.SlateGray] = Color.FromArgb(-9404272); + ColorToKnownColor[-1286] = KnownColor.Snow; + KnownColorToColor[KnownColor.Snow] = Color.FromArgb(-1286); + ColorToKnownColor[-16711809] = KnownColor.SpringGreen; + KnownColorToColor[KnownColor.SpringGreen] = Color.FromArgb(-16711809); + ColorToKnownColor[-12156236] = KnownColor.SteelBlue; + KnownColorToColor[KnownColor.SteelBlue] = Color.FromArgb(-12156236); + ColorToKnownColor[-2968436] = KnownColor.Tan; + KnownColorToColor[KnownColor.Tan] = Color.FromArgb(-2968436); + ColorToKnownColor[-16744320] = KnownColor.Teal; + KnownColorToColor[KnownColor.Teal] = Color.FromArgb(-16744320); + ColorToKnownColor[-2572328] = KnownColor.Thistle; + KnownColorToColor[KnownColor.Thistle] = Color.FromArgb(-2572328); + ColorToKnownColor[-40121] = KnownColor.Tomato; + KnownColorToColor[KnownColor.Tomato] = Color.FromArgb(-40121); + ColorToKnownColor[-12525360] = KnownColor.Turquoise; + KnownColorToColor[KnownColor.Turquoise] = Color.FromArgb(-12525360); + ColorToKnownColor[-1146130] = KnownColor.Violet; + KnownColorToColor[KnownColor.Violet] = Color.FromArgb(-1146130); + ColorToKnownColor[-663885] = KnownColor.Wheat; + KnownColorToColor[KnownColor.Wheat] = Color.FromArgb(-663885); + ColorToKnownColor[-1] = KnownColor.White; + KnownColorToColor[KnownColor.White] = Color.FromArgb(-1); + ColorToKnownColor[-657931] = KnownColor.WhiteSmoke; + KnownColorToColor[KnownColor.WhiteSmoke] = Color.FromArgb(-657931); + ColorToKnownColor[-256] = KnownColor.Yellow; + KnownColorToColor[KnownColor.Yellow] = Color.FromArgb(-256); + ColorToKnownColor[-6632142] = KnownColor.YellowGreen; + KnownColorToColor[KnownColor.YellowGreen] = Color.FromArgb(-6632142); + ColorToKnownColor[-986896] = KnownColor.ButtonFace; + KnownColorToColor[KnownColor.ButtonFace] = Color.FromArgb(-986896); + ColorToKnownColor[-1] = KnownColor.ButtonHighlight; + KnownColorToColor[KnownColor.ButtonHighlight] = Color.FromArgb(-1); + ColorToKnownColor[-6250336] = KnownColor.ButtonShadow; + KnownColorToColor[KnownColor.ButtonShadow] = Color.FromArgb(-6250336); + ColorToKnownColor[-4599318] = KnownColor.GradientActiveCaption; + KnownColorToColor[KnownColor.GradientActiveCaption] = Color.FromArgb(-4599318); + ColorToKnownColor[-2628366] = KnownColor.GradientInactiveCaption; + KnownColorToColor[KnownColor.GradientInactiveCaption] = Color.FromArgb(-2628366); + ColorToKnownColor[-986896] = KnownColor.MenuBar; + KnownColorToColor[KnownColor.MenuBar] = Color.FromArgb(-986896); + ColorToKnownColor[-16746281] = KnownColor.MenuHighlight; + KnownColorToColor[KnownColor.MenuHighlight] = Color.FromArgb(-16746281); + } + public static bool IsKnownColor(Color color) { - return color.IsNamedColor; + return ColorToKnownColor.ContainsKey(color.ToArgb()); } - public static KnownColor ToKnownColor(Color c) + public static KnownColor ToKnownColor(Color color) { - KnownColor color; - if (Enum.TryParse(c.Name, out color)) - return color; - return default(KnownColor); + if (ColorToKnownColor.TryGetValue(color.ToArgb(), out KnownColor result)) + return result; + return KnownColor.Transparent; } public static Color FromKnownColor(KnownColor knownColor) { - return Color.FromName(knownColor.ToString()); + if (KnownColorToColor.TryGetValue(knownColor, out Color result)) + return result; + return Color.Transparent; } public static bool IsSystemColor(Color c) @@ -35,3 +572,6 @@ public static bool IsSystemColor(Color c) } } } +#endif + + diff --git a/FastReport.OpenSource/DotNetClasses/Color.Full.cs b/FastReport.OpenSource/DotNetClasses/Color.Full.cs index bd82b647..f6cb89c9 100644 --- a/FastReport.OpenSource/DotNetClasses/Color.Full.cs +++ b/FastReport.OpenSource/DotNetClasses/Color.Full.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; using System.Text; -#if !NETSTANDARD2_0 +#if !(NETSTANDARD2_0 || NETSTANDARD2_1) namespace System.Drawing { internal class ColorExt diff --git a/FastReport.OpenSource/DotNetClasses/ColorConverter.cs b/FastReport.OpenSource/DotNetClasses/ColorConverter.cs index 635a39ed..75c2c779 100644 --- a/FastReport.OpenSource/DotNetClasses/ColorConverter.cs +++ b/FastReport.OpenSource/DotNetClasses/ColorConverter.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -476,3 +477,4 @@ public int Compare(object left, object right) // return (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFromInvariantString(value); //} } +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/ColorTranslator.cs b/FastReport.OpenSource/DotNetClasses/ColorTranslator.cs index 95264c02..83a1bd39 100644 --- a/FastReport.OpenSource/DotNetClasses/ColorTranslator.cs +++ b/FastReport.OpenSource/DotNetClasses/ColorTranslator.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; @@ -7,172 +8,173 @@ namespace System.Drawing { - internal class ColorTranslator - { - - private static Hashtable htmlSysColorTable; - - - public static string ToHtml(Color c) - { - string colorString = String.Empty; - - if (c.IsEmpty) - return colorString; - bool flag = true; - if (ColorExt.IsKnownColor(c)) - { - flag = false; - switch (ColorExt.ToKnownColor(c)) - { - case KnownColor.ActiveBorder: colorString = "activeborder"; break; - case KnownColor.GradientActiveCaption: - case KnownColor.ActiveCaption: colorString = "activecaption"; break; - case KnownColor.AppWorkspace: colorString = "appworkspace"; break; - case KnownColor.Desktop: colorString = "background"; break; - case KnownColor.Control: colorString = "buttonface"; break; - case KnownColor.ControlLight: colorString = "buttonface"; break; - case KnownColor.ControlDark: colorString = "buttonshadow"; break; - case KnownColor.ControlText: colorString = "buttontext"; break; - case KnownColor.ActiveCaptionText: colorString = "captiontext"; break; - case KnownColor.GrayText: colorString = "graytext"; break; - case KnownColor.HotTrack: - case KnownColor.Highlight: colorString = "highlight"; break; - case KnownColor.MenuHighlight: - case KnownColor.HighlightText: colorString = "highlighttext"; break; - case KnownColor.InactiveBorder: colorString = "inactiveborder"; break; - case KnownColor.GradientInactiveCaption: - case KnownColor.InactiveCaption: colorString = "inactivecaption"; break; - case KnownColor.InactiveCaptionText: colorString = "inactivecaptiontext"; break; - case KnownColor.Info: colorString = "infobackground"; break; - case KnownColor.InfoText: colorString = "infotext"; break; - case KnownColor.MenuBar: - case KnownColor.Menu: colorString = "menu"; break; - case KnownColor.MenuText: colorString = "menutext"; break; - case KnownColor.ScrollBar: colorString = "scrollbar"; break; - case KnownColor.ControlDarkDark: colorString = "threeddarkshadow"; break; - case KnownColor.ControlLightLight: colorString = "buttonhighlight"; break; - case KnownColor.Window: colorString = "window"; break; - case KnownColor.WindowFrame: colorString = "windowframe"; break; - case KnownColor.WindowText: colorString = "windowtext"; break; - default: flag = true; break; - } - } - if (flag) - { - if (c.IsNamedColor) - { - if (c == Color.LightGray) - { - // special case due to mismatch between Html and enum spelling - colorString = "LightGrey"; - } - else - { - colorString = c.Name; - } - } - else - { - colorString = "#" + c.R.ToString("X2", null) + - c.G.ToString("X2", null) + - c.B.ToString("X2", null); - } - } - return colorString; - } - - public static Color FromHtml(string htmlColor) - { - Color c = Color.Empty; - - // empty color - if ((htmlColor == null) || (htmlColor.Length == 0)) - return c; - - // #RRGGBB or #RGB - if ((htmlColor[0] == '#') && - ((htmlColor.Length == 7) || (htmlColor.Length == 4))) - { - - if (htmlColor.Length == 7) - { - c = Color.FromArgb(Convert.ToInt32(htmlColor.Substring(1, 2), 16), - Convert.ToInt32(htmlColor.Substring(3, 2), 16), - Convert.ToInt32(htmlColor.Substring(5, 2), 16)); - } - else - { - string r = Char.ToString(htmlColor[1]); - string g = Char.ToString(htmlColor[2]); - string b = Char.ToString(htmlColor[3]); - - c = Color.FromArgb(Convert.ToInt32(r + r, 16), - Convert.ToInt32(g + g, 16), - Convert.ToInt32(b + b, 16)); - } - } - - // special case. Html requires LightGrey, but .NET uses LightGray - if (c.IsEmpty && String.Equals(htmlColor, "LightGrey", StringComparison.OrdinalIgnoreCase)) - { - c = Color.LightGray; - } - - // System color - if (c.IsEmpty) - { - if (htmlSysColorTable == null) - { - InitializeHtmlSysColorTable(); - } - - object o = htmlSysColorTable[htmlColor.ToLower(CultureInfo.InvariantCulture)]; - if (o != null) - { - c = (Color)o; - } - } - - // resort to type converter which will handle named colors - if (c.IsEmpty) - { - c = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFromString(htmlColor); - } - - return c; - } - - private static void InitializeHtmlSysColorTable() - { - htmlSysColorTable = new Hashtable(26); - htmlSysColorTable["activeborder"] = ColorExt.FromKnownColor(KnownColor.ActiveBorder); - htmlSysColorTable["activecaption"] = ColorExt.FromKnownColor(KnownColor.ActiveCaption); - htmlSysColorTable["appworkspace"] = ColorExt.FromKnownColor(KnownColor.AppWorkspace); - htmlSysColorTable["background"] = ColorExt.FromKnownColor(KnownColor.Desktop); - htmlSysColorTable["buttonface"] = ColorExt.FromKnownColor(KnownColor.Control); - htmlSysColorTable["buttonhighlight"] = ColorExt.FromKnownColor(KnownColor.ControlLightLight); - htmlSysColorTable["buttonshadow"] = ColorExt.FromKnownColor(KnownColor.ControlDark); - htmlSysColorTable["buttontext"] = ColorExt.FromKnownColor(KnownColor.ControlText); - htmlSysColorTable["captiontext"] = ColorExt.FromKnownColor(KnownColor.ActiveCaptionText); - htmlSysColorTable["graytext"] = ColorExt.FromKnownColor(KnownColor.GrayText); - htmlSysColorTable["highlight"] = ColorExt.FromKnownColor(KnownColor.Highlight); - htmlSysColorTable["highlighttext"] = ColorExt.FromKnownColor(KnownColor.HighlightText); - htmlSysColorTable["inactiveborder"] = ColorExt.FromKnownColor(KnownColor.InactiveBorder); - htmlSysColorTable["inactivecaption"] = ColorExt.FromKnownColor(KnownColor.InactiveCaption); - htmlSysColorTable["inactivecaptiontext"] = ColorExt.FromKnownColor(KnownColor.InactiveCaptionText); - htmlSysColorTable["infobackground"] = ColorExt.FromKnownColor(KnownColor.Info); - htmlSysColorTable["infotext"] = ColorExt.FromKnownColor(KnownColor.InfoText); - htmlSysColorTable["menu"] = ColorExt.FromKnownColor(KnownColor.Menu); - htmlSysColorTable["menutext"] = ColorExt.FromKnownColor(KnownColor.MenuText); - htmlSysColorTable["scrollbar"] = ColorExt.FromKnownColor(KnownColor.ScrollBar); - htmlSysColorTable["threeddarkshadow"] = ColorExt.FromKnownColor(KnownColor.ControlDarkDark); - htmlSysColorTable["threedface"] = ColorExt.FromKnownColor(KnownColor.Control); - htmlSysColorTable["threedhighlight"] = ColorExt.FromKnownColor(KnownColor.ControlLight); - htmlSysColorTable["threedlightshadow"] = ColorExt.FromKnownColor(KnownColor.ControlLightLight); - htmlSysColorTable["window"] = ColorExt.FromKnownColor(KnownColor.Window); - htmlSysColorTable["windowframe"] = ColorExt.FromKnownColor(KnownColor.WindowFrame); - htmlSysColorTable["windowtext"] = ColorExt.FromKnownColor(KnownColor.WindowText); - } - } + //internal class ColorTranslator + //{ + + // private static Hashtable htmlSysColorTable; + + + // public static string ToHtml(Color c) + // { + // string colorString = String.Empty; + + // if (c.IsEmpty) + // return colorString; + // bool flag = true; + // if (ColorExt.IsKnownColor(c)) + // { + // flag = false; + // switch (ColorExt.ToKnownColor(c)) + // { + // case KnownColor.ActiveBorder: colorString = "activeborder"; break; + // case KnownColor.GradientActiveCaption: + // case KnownColor.ActiveCaption: colorString = "activecaption"; break; + // case KnownColor.AppWorkspace: colorString = "appworkspace"; break; + // case KnownColor.Desktop: colorString = "background"; break; + // case KnownColor.Control: colorString = "buttonface"; break; + // case KnownColor.ControlLight: colorString = "buttonface"; break; + // case KnownColor.ControlDark: colorString = "buttonshadow"; break; + // case KnownColor.ControlText: colorString = "buttontext"; break; + // case KnownColor.ActiveCaptionText: colorString = "captiontext"; break; + // case KnownColor.GrayText: colorString = "graytext"; break; + // case KnownColor.HotTrack: + // case KnownColor.Highlight: colorString = "highlight"; break; + // case KnownColor.MenuHighlight: + // case KnownColor.HighlightText: colorString = "highlighttext"; break; + // case KnownColor.InactiveBorder: colorString = "inactiveborder"; break; + // case KnownColor.GradientInactiveCaption: + // case KnownColor.InactiveCaption: colorString = "inactivecaption"; break; + // case KnownColor.InactiveCaptionText: colorString = "inactivecaptiontext"; break; + // case KnownColor.Info: colorString = "infobackground"; break; + // case KnownColor.InfoText: colorString = "infotext"; break; + // case KnownColor.MenuBar: + // case KnownColor.Menu: colorString = "menu"; break; + // case KnownColor.MenuText: colorString = "menutext"; break; + // case KnownColor.ScrollBar: colorString = "scrollbar"; break; + // case KnownColor.ControlDarkDark: colorString = "threeddarkshadow"; break; + // case KnownColor.ControlLightLight: colorString = "buttonhighlight"; break; + // case KnownColor.Window: colorString = "window"; break; + // case KnownColor.WindowFrame: colorString = "windowframe"; break; + // case KnownColor.WindowText: colorString = "windowtext"; break; + // default: flag = true; break; + // } + // } + // if (flag) + // { + // if (c.IsNamedColor) + // { + // if (c == Color.LightGray) + // { + // // special case due to mismatch between Html and enum spelling + // colorString = "LightGrey"; + // } + // else + // { + // colorString = c.Name; + // } + // } + // else + // { + // colorString = "#" + c.R.ToString("X2", null) + + // c.G.ToString("X2", null) + + // c.B.ToString("X2", null); + // } + // } + // return colorString; + // } + + // public static Color FromHtml(string htmlColor) + // { + // Color c = Color.Empty; + + // // empty color + // if ((htmlColor == null) || (htmlColor.Length == 0)) + // return c; + + // // #RRGGBB or #RGB + // if ((htmlColor[0] == '#') && + // ((htmlColor.Length == 7) || (htmlColor.Length == 4))) + // { + + // if (htmlColor.Length == 7) + // { + // c = Color.FromArgb(Convert.ToInt32(htmlColor.Substring(1, 2), 16), + // Convert.ToInt32(htmlColor.Substring(3, 2), 16), + // Convert.ToInt32(htmlColor.Substring(5, 2), 16)); + // } + // else + // { + // string r = Char.ToString(htmlColor[1]); + // string g = Char.ToString(htmlColor[2]); + // string b = Char.ToString(htmlColor[3]); + + // c = Color.FromArgb(Convert.ToInt32(r + r, 16), + // Convert.ToInt32(g + g, 16), + // Convert.ToInt32(b + b, 16)); + // } + // } + + // // special case. Html requires LightGrey, but .NET uses LightGray + // if (c.IsEmpty && String.Equals(htmlColor, "LightGrey", StringComparison.OrdinalIgnoreCase)) + // { + // c = Color.LightGray; + // } + + // // System color + // if (c.IsEmpty) + // { + // if (htmlSysColorTable == null) + // { + // InitializeHtmlSysColorTable(); + // } + + // object o = htmlSysColorTable[htmlColor.ToLower(CultureInfo.InvariantCulture)]; + // if (o != null) + // { + // c = (Color)o; + // } + // } + + // // resort to type converter which will handle named colors + // if (c.IsEmpty) + // { + // c = (Color)TypeDescriptor.GetConverter(typeof(Color)).ConvertFromString(htmlColor); + // } + + // return c; + // } + + // private static void InitializeHtmlSysColorTable() + // { + // htmlSysColorTable = new Hashtable(26); + // htmlSysColorTable["activeborder"] = ColorExt.FromKnownColor(KnownColor.ActiveBorder); + // htmlSysColorTable["activecaption"] = ColorExt.FromKnownColor(KnownColor.ActiveCaption); + // htmlSysColorTable["appworkspace"] = ColorExt.FromKnownColor(KnownColor.AppWorkspace); + // htmlSysColorTable["background"] = ColorExt.FromKnownColor(KnownColor.Desktop); + // htmlSysColorTable["buttonface"] = ColorExt.FromKnownColor(KnownColor.Control); + // htmlSysColorTable["buttonhighlight"] = ColorExt.FromKnownColor(KnownColor.ControlLightLight); + // htmlSysColorTable["buttonshadow"] = ColorExt.FromKnownColor(KnownColor.ControlDark); + // htmlSysColorTable["buttontext"] = ColorExt.FromKnownColor(KnownColor.ControlText); + // htmlSysColorTable["captiontext"] = ColorExt.FromKnownColor(KnownColor.ActiveCaptionText); + // htmlSysColorTable["graytext"] = ColorExt.FromKnownColor(KnownColor.GrayText); + // htmlSysColorTable["highlight"] = ColorExt.FromKnownColor(KnownColor.Highlight); + // htmlSysColorTable["highlighttext"] = ColorExt.FromKnownColor(KnownColor.HighlightText); + // htmlSysColorTable["inactiveborder"] = ColorExt.FromKnownColor(KnownColor.InactiveBorder); + // htmlSysColorTable["inactivecaption"] = ColorExt.FromKnownColor(KnownColor.InactiveCaption); + // htmlSysColorTable["inactivecaptiontext"] = ColorExt.FromKnownColor(KnownColor.InactiveCaptionText); + // htmlSysColorTable["infobackground"] = ColorExt.FromKnownColor(KnownColor.Info); + // htmlSysColorTable["infotext"] = ColorExt.FromKnownColor(KnownColor.InfoText); + // htmlSysColorTable["menu"] = ColorExt.FromKnownColor(KnownColor.Menu); + // htmlSysColorTable["menutext"] = ColorExt.FromKnownColor(KnownColor.MenuText); + // htmlSysColorTable["scrollbar"] = ColorExt.FromKnownColor(KnownColor.ScrollBar); + // htmlSysColorTable["threeddarkshadow"] = ColorExt.FromKnownColor(KnownColor.ControlDarkDark); + // htmlSysColorTable["threedface"] = ColorExt.FromKnownColor(KnownColor.Control); + // htmlSysColorTable["threedhighlight"] = ColorExt.FromKnownColor(KnownColor.ControlLight); + // htmlSysColorTable["threedlightshadow"] = ColorExt.FromKnownColor(KnownColor.ControlLightLight); + // htmlSysColorTable["window"] = ColorExt.FromKnownColor(KnownColor.Window); + // htmlSysColorTable["windowframe"] = ColorExt.FromKnownColor(KnownColor.WindowFrame); + // htmlSysColorTable["windowtext"] = ColorExt.FromKnownColor(KnownColor.WindowText); + // } + //} } +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/CompilerError.cs b/FastReport.OpenSource/DotNetClasses/CompilerError.cs index f3c10774..5a7a01ec 100644 --- a/FastReport.OpenSource/DotNetClasses/CompilerError.cs +++ b/FastReport.OpenSource/DotNetClasses/CompilerError.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections.Generic; using System.Text; @@ -12,3 +13,5 @@ internal class CompilerError public object ErrorNumber { get; internal set; } } } + +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/CompilerParameters.cs b/FastReport.OpenSource/DotNetClasses/CompilerParameters.cs index b8308315..adae6d3e 100644 --- a/FastReport.OpenSource/DotNetClasses/CompilerParameters.cs +++ b/FastReport.OpenSource/DotNetClasses/CompilerParameters.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections.Generic; using System.Collections.Specialized; using System.Text; @@ -12,3 +13,5 @@ internal class CompilerParameters public TempFileCollection TempFiles { get; internal set; } = new TempFileCollection("", false); } } + +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/CompilerResults.cs b/FastReport.OpenSource/DotNetClasses/CompilerResults.cs index ecd09adb..9d77efe2 100644 --- a/FastReport.OpenSource/DotNetClasses/CompilerResults.cs +++ b/FastReport.OpenSource/DotNetClasses/CompilerResults.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections.Generic; using System.Reflection; using System.Text; @@ -11,3 +12,5 @@ internal class CompilerResults public Assembly CompiledAssembly { get; internal set; } = null; } } + +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/SystemColors.cs b/FastReport.OpenSource/DotNetClasses/SystemColors.cs index d7bb74ab..4e22c9b0 100644 --- a/FastReport.OpenSource/DotNetClasses/SystemColors.cs +++ b/FastReport.OpenSource/DotNetClasses/SystemColors.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections.Generic; using System.Text; @@ -42,3 +43,5 @@ internal static class SystemColors public static Color WindowText => ColorExt.FromKnownColor(KnownColor.WindowText); } } + +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/TempFileCollection.cs b/FastReport.OpenSource/DotNetClasses/TempFileCollection.cs index 23e562a3..fff11dba 100644 --- a/FastReport.OpenSource/DotNetClasses/TempFileCollection.cs +++ b/FastReport.OpenSource/DotNetClasses/TempFileCollection.cs @@ -1,4 +1,5 @@ -using System; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; using System.Collections.Generic; using System.Text; @@ -16,3 +17,5 @@ public TempFileCollection(string tempFolder, bool v) } } } + +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/UITypeEditor.cs b/FastReport.OpenSource/DotNetClasses/UITypeEditor.cs new file mode 100644 index 00000000..717125ae --- /dev/null +++ b/FastReport.OpenSource/DotNetClasses/UITypeEditor.cs @@ -0,0 +1,10 @@ +#if NETSTANDARD2_1 || NETSTANDARD2_0 + +namespace System.Drawing.Design +{ + class UITypeEditor + { + + } +} +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/VBCodeProvider.cs b/FastReport.OpenSource/DotNetClasses/VBCodeProvider.cs index 59171530..f31f0d63 100644 --- a/FastReport.OpenSource/DotNetClasses/VBCodeProvider.cs +++ b/FastReport.OpenSource/DotNetClasses/VBCodeProvider.cs @@ -1,4 +1,5 @@ -using Microsoft.CodeAnalysis; +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.VisualBasic; using System; using System.CodeDom.Compiler; @@ -31,6 +32,8 @@ public override CompilerResults CompileAssemblyFromSource(CompilerParameters cp, AddExtraAssemblies(cp.ReferencedAssemblies, references); + + Compilation compilation = VisualBasicCompilation.Create( "_" + Guid.NewGuid().ToString("D"), new SyntaxTree[] { codeTree }, references: references, options: options.WithEmbedVbCoreRuntime(true) @@ -78,3 +81,4 @@ public override void Dispose() } } +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.BindingSource.cs b/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.BindingSource.cs index 64eabd6b..5890b8d2 100644 --- a/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.BindingSource.cs +++ b/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.BindingSource.cs @@ -1,3 +1,4 @@ +#if NETSTANDARD2_0 || NETSTANDARD2_1 // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including @@ -145,3 +146,5 @@ public virtual PropertyDescriptorCollection GetItemProperties(PropertyDescriptor } } } + +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.ListBindingHelper.cs b/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.ListBindingHelper.cs index 1527ae18..06b4b724 100644 --- a/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.ListBindingHelper.cs +++ b/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.ListBindingHelper.cs @@ -1,3 +1,4 @@ +#if NETSTANDARD2_0 || NETSTANDARD2_1 // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including @@ -176,3 +177,4 @@ static PropertyInfo GetPropertyByReflection(Type type, string property_name) } } } +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.cs b/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.cs index 8e2f42a0..37df4074 100644 --- a/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.cs +++ b/FastReport.OpenSource/DotNetClasses/WindowsFormsReplacement.cs @@ -1,3 +1,4 @@ +#if NETSTANDARD2_0 || NETSTANDARD2_1 using System; using System.Collections.Generic; using System.Text; @@ -870,4 +871,5 @@ public static void DoEvents() #pragma warning restore FR0000 // Field must be texted in lowerCamelCase. -#pragma warning restore 1591 \ No newline at end of file +#pragma warning restore 1591 +#endif \ No newline at end of file diff --git a/FastReport.OpenSource/FastReport.OpenSource.csproj b/FastReport.OpenSource/FastReport.OpenSource.csproj index d0edde21..3ee808a5 100644 --- a/FastReport.OpenSource/FastReport.OpenSource.csproj +++ b/FastReport.OpenSource/FastReport.OpenSource.csproj @@ -1,7 +1,7 @@  - net40;netstandard2.0 + net40;netstandard2.0;netstandard2.1 @@ -32,21 +32,23 @@ Various report objects will allow your report to look exactly how you want it to TRACE;DOTNET_4; - - + + + + - + - + @@ -54,6 +56,7 @@ Various report objects will allow your report to look exactly how you want it to + @@ -62,4 +65,5 @@ Various report objects will allow your report to look exactly how you want it to Resources\%(RecursiveDir)%(Filename)%(Extension) + \ No newline at end of file diff --git a/FastReport.OpenSource/TypeConverters/FontConverter.cs b/FastReport.OpenSource/TypeConverters/FontConverter.cs new file mode 100644 index 00000000..a5f7ca41 --- /dev/null +++ b/FastReport.OpenSource/TypeConverters/FontConverter.cs @@ -0,0 +1,386 @@ +// +// System.Drawing.FontConverter.cs +// +// Authors: +// Dennis Hayes (dennish@Raytek.com) +// Gonzalo Paniagua Javier (gonzalo@ximian.com) +// Ravindra (rkumar@novell.com) +// +// Copyright (C) 2002,2003 Ximian, Inc. http://www.ximian.com +// +// Copyright (C) 2004-2006 Novell, Inc (http://www.novell.com) +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +// +#if NETSTANDARD2_0 || NETSTANDARD2_1 +using System; +using System.Text; +using System.Collections; +using System.ComponentModel; +using System.Globalization; +using System.Drawing.Text; +using System.ComponentModel.Design.Serialization; +using System.Reflection; +using System.Drawing; + +namespace FastReport.TypeConverters +{ + public class FontConverter : TypeConverter + { + public static FontConverter Instance { get; } = new FontConverter(); + public FontConverter () + { + } + ~FontConverter () + { + // required to match API definition + } + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof (string)) + return true; + + return base.CanConvertFrom (context, sourceType); + } + + public override bool CanConvertTo (ITypeDescriptorContext context, Type destinationType) + { + if (destinationType == typeof (String)) + return true; + + if (destinationType == typeof (InstanceDescriptor)) + return true; + + return base.CanConvertTo (context, destinationType); + } + + public override object ConvertTo (ITypeDescriptorContext context, + CultureInfo culture, + object value, + Type destinationType) + { + if ((destinationType == typeof (string)) && (value is Font)) { + Font font = (Font) value; + StringBuilder sb = new StringBuilder (); + sb.Append (font.Name).Append (culture.TextInfo.ListSeparator[0] + " "); + sb.Append (font.Size); + + switch (font.Unit) { + // MS throws ArgumentException, if unit is set + // to GraphicsUnit.Display + // Don't know what to append for GraphicsUnit.Display + case GraphicsUnit.Display: + sb.Append ("display"); break; + + case GraphicsUnit.Document: + sb.Append ("doc"); break; + + case GraphicsUnit.Point: + sb.Append ("pt"); break; + + case GraphicsUnit.Inch: + sb.Append ("in"); break; + + case GraphicsUnit.Millimeter: + sb.Append ("mm"); break; + + case GraphicsUnit.Pixel: + sb.Append ("px"); break; + + case GraphicsUnit.World: + sb.Append ("world"); break; + } + + if (font.Style != FontStyle.Regular) + sb.Append (culture.TextInfo.ListSeparator[0] + " style=").Append (font.Style); + + return sb.ToString (); + } + + if ((destinationType == typeof (InstanceDescriptor)) && (value is Font)) { + Font font = (Font) value; + ConstructorInfo met = typeof(Font).GetTypeInfo ().GetConstructor (new Type[] {typeof(string), typeof(float), typeof(FontStyle), typeof(GraphicsUnit)}); + object[] args = new object[4]; + args [0] = font.Name; + args [1] = font.Size; + args [2] = font.Style; + args [3] = font.Unit; + return new InstanceDescriptor (met, args); + } + + return base.ConvertTo (context, culture, value, destinationType); + } + + public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) + { + FontStyle f_style; + float f_size; + GraphicsUnit f_unit; + string font; + string units; + string[] fields; + + if (! (value is string)) { + return base.ConvertFrom (context, culture, value); + } + + font = (string)value; + font = font.Trim (); + + if (font.Length == 0) { + return null; + } + + if (culture == null) { + culture = CultureInfo.CurrentCulture; + } + + // Format is FontFamily, size[[, style=1,2,3]] + // This is a bit tricky since the comma can be used for styles and fields + fields = font.Split(new char[] {culture.TextInfo.ListSeparator[0]}); + if (fields.Length < 1) { + throw new ArgumentException("Failed to parse font format"); + } + + font = fields[0]; + f_size = 8f; + units = "px"; + f_unit = GraphicsUnit.Pixel; + if (fields.Length > 1) { // We have a size + for (int i = 0; i < fields[1].Length; i++) { + if (Char.IsLetter(fields[1][i])) { + f_size = (float)TypeDescriptor.GetConverter(typeof(float)).ConvertFromString(context, culture, fields[1].Substring(0, i)); + units = fields[1].Substring(i); + break; + } + } + if (units == "display") { + f_unit = GraphicsUnit.Display; + } else if (units == "doc") { + f_unit = GraphicsUnit.Document; + } else if (units == "pt") { + f_unit = GraphicsUnit.Point; + } else if (units == "in") { + f_unit = GraphicsUnit.Inch; + } else if (units == "mm") { + f_unit = GraphicsUnit.Millimeter; + } else if (units == "px") { + f_unit = GraphicsUnit.Pixel; + } else if (units == "world") { + f_unit = GraphicsUnit.World; + } + } + + f_style = FontStyle.Regular; + if (fields.Length > 2) { // We have style + string compare; + + for (int i = 2; i < fields.Length; i++) { + compare = fields[i]; + + if (compare.IndexOf("Regular") != -1) { + f_style |= FontStyle.Regular; + } + if (compare.IndexOf("Bold") != -1) { + f_style |= FontStyle.Bold; + } + if (compare.IndexOf("Italic") != -1) { + f_style |= FontStyle.Italic; + } + if (compare.IndexOf("Strikeout") != -1) { + f_style |= FontStyle.Strikeout; + } + if (compare.IndexOf("Underline") != -1) { + f_style |= FontStyle.Underline; + } + } + } + + return new Font (font, f_size, f_style, f_unit); + } + + public override object CreateInstance (ITypeDescriptorContext context, IDictionary propertyValues) + { + Object value; + byte charSet = 1; + float size = 8; + String name = null; + bool vertical = false; + FontStyle style = FontStyle.Regular; + FontFamily fontFamily = null; + GraphicsUnit unit = GraphicsUnit.Point; + + if ((value = propertyValues ["GdiCharSet"]) != null) + charSet = (byte) value; + + if ((value = propertyValues ["Size"]) != null) + size = (float) value; + + if ((value = propertyValues ["Unit"]) != null) + unit = (GraphicsUnit) value; + + if ((value = propertyValues ["Name"]) != null) + name = (String) value; + + if ((value = propertyValues ["GdiVerticalFont"]) != null) + vertical = (bool) value; + + if ((value = propertyValues ["Bold"]) != null) { + bool bold = (bool) value; + if (bold == true) + style |= FontStyle.Bold; + } + + if ((value = propertyValues ["Italic"]) != null) { + bool italic = (bool) value; + if (italic == true) + style |= FontStyle.Italic; + } + + if ((value = propertyValues ["Strikeout"]) != null) { + bool strike = (bool) value; + if (strike == true) + style |= FontStyle.Strikeout; + } + + if ((value = propertyValues ["Underline"]) != null) { + bool underline = (bool) value; + if (underline == true) + style |= FontStyle.Underline; + } + + /* ?? Should default font be culture dependent ?? */ + if (name == null) + fontFamily = new FontFamily ("Tahoma"); + else { + name = name.ToLower (); + FontCollection collection = new InstalledFontCollection (); + FontFamily [] installedFontList = collection.Families; + foreach (FontFamily font in installedFontList) { + if (name == font.Name.ToLower ()) { + fontFamily = font; + break; + } + } + + // font family not found in installed fonts + if (fontFamily == null) { + collection = new PrivateFontCollection (); + FontFamily [] privateFontList = collection.Families; + foreach (FontFamily font in privateFontList) { + if (name == font.Name.ToLower ()) { + fontFamily = font; + break; + } + } + } + + // font family not found in private fonts also + if (fontFamily == null) + fontFamily = FontFamily.GenericSansSerif; + } + + return new Font (fontFamily, size, style, unit, charSet, vertical); + } + + public override bool GetCreateInstanceSupported (ITypeDescriptorContext context) + { + return true; + } + + public override PropertyDescriptorCollection GetProperties + (ITypeDescriptorContext context, + object value, Attribute [] attributes) + { + if (value is Font) + return TypeDescriptor.GetProperties (value, attributes); + + return base.GetProperties (context, value, attributes); + } + + public override bool GetPropertiesSupported (ITypeDescriptorContext context) + { + return true; + } + + public sealed class FontNameConverter : TypeConverter + , IDisposable + { + FontFamily [] fonts; + + public FontNameConverter () + { + fonts = FontFamily.Families; + } + void IDisposable.Dispose () + { + } + public override bool CanConvertFrom (ITypeDescriptorContext context, Type sourceType) + { + if (sourceType == typeof (string)) + return true; + + return base.CanConvertFrom (context, sourceType); + } + + public override object ConvertFrom (ITypeDescriptorContext context, CultureInfo culture, object value) + { + if (value is string) + return value; + return base.ConvertFrom (context, culture, value); + } + + public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) + { + string [] values = new string [fonts.Length]; + for (int i = fonts.Length; i > 0;){ + i--; + values [i] = fonts [i].Name; + } + + return new TypeConverter.StandardValuesCollection (values); + } + + public override bool GetStandardValuesExclusive (ITypeDescriptorContext context) + { + // We allow other values other than those in the font list. + return false; + } + + public override bool GetStandardValuesSupported (ITypeDescriptorContext context) + { + // Yes, we support picking an element from the list. + return true; + } + } + + public class FontUnitConverter : EnumConverter + { + public FontUnitConverter () : base (typeof (GraphicsUnit)) {} + + public override StandardValuesCollection GetStandardValues (ITypeDescriptorContext context) + { + return base.GetStandardValues (context); + } + + } + } +} +#endif \ No newline at end of file diff --git a/FastReport/Resources/buttons.png b/FastReport/Resources/buttons.png index 576d1439..971bc0c1 100644 Binary files a/FastReport/Resources/buttons.png and b/FastReport/Resources/buttons.png differ diff --git a/FastReport/Resources/en.xml b/FastReport/Resources/en.xml index d0097b53..f99b1714 100644 --- a/FastReport/Resources/en.xml +++ b/FastReport/Resources/en.xml @@ -88,6 +88,7 @@ + @@ -299,6 +300,7 @@ + @@ -427,6 +429,7 @@ + @@ -535,10 +538,12 @@ - + + + @@ -1586,6 +1591,8 @@ + + @@ -1760,6 +1767,13 @@ + + + + + + + @@ -1936,6 +1950,11 @@ + + + + + @@ -2136,6 +2155,7 @@ + diff --git a/Tools/FastReport.Tests.OpenSource/Data/JsonConnectionTests.cs b/Tools/FastReport.Tests.OpenSource/Data/JsonConnectionTests.cs new file mode 100644 index 00000000..b1e97cd5 --- /dev/null +++ b/Tools/FastReport.Tests.OpenSource/Data/JsonConnectionTests.cs @@ -0,0 +1,175 @@ +using FastReport.Data.JsonConnection; +using System; +using System.Collections.Generic; +using System.Text; +using Xunit; + +namespace FastReport.Tests.OpenSource.Data +{ + + public class JsonConnectionTests + { + + [Fact] + public void EmptyTextTest() + { + Assert.Throws(() => JsonBase.FromString("")); + } + + [Theory] + [InlineData("{}")] + [InlineData(" { } ")] + [InlineData(" {}")] + [InlineData("{ \n} ")] + public void EmptyObjectTest(string jsonText) + { + Assert.IsType(JsonBase.FromString(jsonText)); + } + + [Theory] + [InlineData("[]")] + [InlineData(" [ ] ")] + [InlineData(" []")] + [InlineData("[ \n] ")] + public void EmptyArrayTest(string jsonText) + { + Assert.IsType(JsonBase.FromString(jsonText)); + } + + [Theory] + [InlineData("[0.1]", 0.1)] + [InlineData("[0.1e010]", 0.1e010)] + [InlineData("[0.10]", 0.10)] + [InlineData("[0.01e010]", 0.01e010)] + [InlineData("[-0.1]", -0.1)] + [InlineData("[0.1e-010]", 0.1e-010)] + [InlineData("[51251.1]", 51251.1)] + [InlineData("[0.1e+010]", 0.1e+010)] + [InlineData("[-0010.1]", -0010.1)] + [InlineData("[5e110]", 5e110)] + [InlineData("[-1]", -1)] + [InlineData("[-5]", -5)] + [InlineData("[7]", 7)] + [InlineData("[7312312]", 7312312)] + [InlineData("[-12317]", -12317)] + public void ReadNumberTest(string jsonText, double number) + { + JsonBase obj = JsonBase.FromString(jsonText); + + Assert.IsType(obj); + Assert.Single(obj as JsonArray); + Assert.IsType((obj as JsonArray)[0]); + Assert.Equal(number, ((obj as JsonArray)[0] as JsonNumber).Value, 1); + } + + [Theory] + [InlineData("{\"key\":0}", "key")] + [InlineData("{\"\\uabcdkey\":0}", "\uabcdkey")] + [InlineData("{\"\\uabCdkey\":0}", "\uabCdkey")] + [InlineData("{\"\\u0001key\":0}", "\u0001key")] + [InlineData("{\"\\u00Cdkey\":0}", "\u00Cdkey")] + [InlineData("{\"\\uab00key\":0}", "\uab00key")] + [InlineData("{\"\\r\":0}", "\r")] + [InlineData("{\"\\t\":0}", "\t")] + [InlineData("{\"\\n\\n\":0}", "\n\n")] + [InlineData("{\"\\f\":0}", "\f")] + [InlineData("{\"\\b\":0}", "\b")] + [InlineData("{\"\\\\\":0}", "\\")] + [InlineData("{\"\\/\":0}", "/")] + [InlineData("{\"\\\"\":0}", "\"")] + public void ReadKeyTest(string jsonText, string key) + { + JsonBase obj = JsonBase.FromString(jsonText); + + Assert.IsType(obj); + Assert.Single(obj as JsonObject); + Assert.Contains(key, (obj as JsonObject).Keys); + } + + [Theory] + [InlineData("{ \n\t\"true\": true}", "true", true)] + [InlineData("{\"true\":false }", "true", false)] + public void ReadBool(string jsonText, string key, bool value) + { + JsonBase obj = JsonBase.FromString(jsonText); + + Assert.IsType(obj); + Assert.Single(obj as JsonObject); + Assert.Contains(key, (obj as JsonObject).Keys); + Assert.IsType((obj as JsonObject)[key]); + Assert.Equal(value, ((obj as JsonObject)[key] as JsonBoolean).Value); + } + + [Theory] + [InlineData("{ \n\t\"true\": null}", "true")] + [InlineData("{\"true\":null }", "true")] + public void ReadNull(string jsonText, string key) + { + JsonBase obj = JsonBase.FromString(jsonText); + + Assert.IsType(obj); + Assert.Single(obj as JsonObject); + Assert.Contains(key, (obj as JsonObject).Keys); + Assert.Null((obj as JsonObject)[key]); + } + + [Fact] + public void TestComplex() + { + string jsonText = @"{ + ""glossary"": { + ""title"": ""example glossary"", + ""GlossDiv"": { + ""title"": ""S"", + ""GlossList"": { + ""GlossEntry"": { + ""ID"": ""SGML"", + ""SortAs"": ""SGML"", + ""GlossTerm"": ""Standard Generalized Markup Language"", + ""Acronym"": ""SGML"", + ""Abbrev"": ""ISO 8879:1986"", + ""GlossDef"": { + ""para"": ""A meta-markup language, used to create markup languages such as DocBook."", + ""GlossSeeAlso"": [""GML"", ""XML""] + }, + ""GlossSee"": ""markup"" + } + } + } + } +}"; + + JsonBase jsonBase = JsonBase.FromString(jsonText); + + Assert.IsType(jsonBase); + + JsonObject obj = jsonBase as JsonObject; + + Assert.Single(obj); + + Assert.IsType(obj["glossary"]); + + obj = obj["glossary"] as JsonObject; + + Assert.Equal(2, obj.Count); + + Assert.IsType(obj["title"]); + + Assert.Equal("example glossary", (obj["title"] as JsonString).Value); + + Assert.IsType(obj["GlossDiv"]); + obj = obj["GlossDiv"] as JsonObject; + + Assert.IsType(obj["GlossList"]); + obj = obj["GlossList"] as JsonObject; + + Assert.IsType(obj["GlossEntry"]); + obj = obj["GlossEntry"] as JsonObject; + + Assert.IsType(obj["GlossDef"]); + obj = obj["GlossDef"] as JsonObject; + + Assert.IsType(obj["GlossSeeAlso"]); + } + } +} diff --git a/Tools/FastReport.Tests.OpenSource/FastReport.Tests.OpenSource.csproj b/Tools/FastReport.Tests.OpenSource/FastReport.Tests.OpenSource.csproj index a5fed2f9..d0f3ef67 100644 --- a/Tools/FastReport.Tests.OpenSource/FastReport.Tests.OpenSource.csproj +++ b/Tools/FastReport.Tests.OpenSource/FastReport.Tests.OpenSource.csproj @@ -1,4 +1,4 @@ - + netcoreapp2.1