diff --git a/FastReport.Base/BandBase.cs b/FastReport.Base/BandBase.cs index fe294ef8..eeaa53a2 100644 --- a/FastReport.Base/BandBase.cs +++ b/FastReport.Base/BandBase.cs @@ -621,6 +621,12 @@ internal void FixHeightWithComponentsShift(float deltaY) } } + /// + public override List Validate() + { + return new List(); + } + /// public override void Serialize(FRWriter writer) { diff --git a/FastReport.Base/Barcode/BarcodeDatamatrix.cs b/FastReport.Base/Barcode/BarcodeDatamatrix.cs index 01f02067..0295af0a 100644 --- a/FastReport.Base/Barcode/BarcodeDatamatrix.cs +++ b/FastReport.Base/Barcode/BarcodeDatamatrix.cs @@ -397,6 +397,15 @@ private void Draw(byte[] data, int dataSize, DmParams dm) private static void MakePadding(byte[] data, int position, int count) { + // set to ascii mode + if ((count > 0) && (position > 0)) + { + if (data[position - 1] != 254) + data[position] = 254; + position++; + count--; + } + //already in ascii mode if (count <= 0) return; @@ -733,7 +742,7 @@ private static int C40OrTextEncodation(byte[] text, int textOffset, int textLeng ptrIn = last0; encPtr = last1; } - if (encPtr / 3 * 2 > dataLength - 2) + if (encPtr / 3 * 2 > dataLength - 1) { return -1; } @@ -744,8 +753,12 @@ private static int C40OrTextEncodation(byte[] text, int textOffset, int textLeng data[dataOffset + ptrOut++] = (byte)(a / 256); data[dataOffset + ptrOut++] = (byte)a; } - data[ptrOut++] = (byte)254; - i = AsciiEncodation(text, ptrIn, textLength - ptrIn, data, ptrOut, dataLength - ptrOut); + i = 0; + if (textLength - ptrIn > 0) + { + data[ptrOut++] = (byte)254; + i = AsciiEncodation(text, ptrIn, textLength - ptrIn, data, ptrOut, dataLength - ptrOut); + } if (i < 0) return i; return ptrOut + i; diff --git a/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs index 6601a670..985ef68d 100644 --- a/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs +++ b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnection.cs @@ -28,6 +28,7 @@ public partial class JsonDataSourceConnection : DataConnectionBase private JsonArray jsonInternal = null; private JsonSchema jsonSchema = null; private string jsonSchemaString = ""; + private bool simpleStructure; #endregion Private Fields @@ -53,6 +54,14 @@ internal JsonSchema JsonSchema } } + internal bool SimpleStructure + { + get + { + return simpleStructure; + } + } + #endregion Internal Properties #region Public Constructors @@ -182,6 +191,7 @@ private void InitConnection() private void InitConnection(bool rebuildSchema) { JsonDataSourceConnectionStringBuilder builder = new JsonDataSourceConnectionStringBuilder(ConnectionString); + simpleStructure = builder.SimpleStructure; JsonBase obj = null; string jsonText = builder.Json.Trim(); if (jsonText.Length > 0) diff --git a/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs index b5d83b51..53960dc1 100644 --- a/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs +++ b/FastReport.Base/Data/JsonConnection/JsonDataSourceConnectionStringBuilder.cs @@ -67,6 +67,8 @@ public string JsonSchema } } + + /// /// Gets or sets json url encoding /// @@ -85,7 +87,102 @@ public string Encoding } } - public Dictionary Headers { get; set; } + /// + /// Set or get headers of the connection string. + /// + /// + /// + /// Returns copy of dictionary. If you need to update values, set the dictionary again! + /// + public Dictionary Headers + { + get + { + var numberformat = CultureInfo.InvariantCulture.NumberFormat; + Dictionary headers = new Dictionary(); + object result; + string header = string.Empty; + string[] splittedHeader; + int headerIteration = 0; + while (TryGetValue("Header" + headerIteration.ToString(numberformat), out result) && result != null) + { + header = (string)result; + + if (!string.IsNullOrWhiteSpace(header)) + { + splittedHeader = header.Split(':'); + + string headerKey = splittedHeader[0], headerVal = splittedHeader[1]; + + if (Regex.IsMatch(headerKey, @"^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?$")) + { + var base64str = Convert.FromBase64String(headerKey); + headerKey = System.Text.Encoding.UTF8.GetString(base64str); + } + + if (Regex.IsMatch(headerVal, @"^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?$")) + { + var base64str = Convert.FromBase64String(headerVal); + headerVal = System.Text.Encoding.UTF8.GetString(base64str); + } + + headers[headerKey] = headerVal; + } + headerIteration++; + } + return headers; + } + set + { + var numberformat = CultureInfo.InvariantCulture.NumberFormat; + int headerIteration = 0; + + while (Remove("Header" + headerIteration.ToString(numberformat))) + { + headerIteration++; + } + + if (value != null) + { + headerIteration = 0; + foreach (var header in value) + { + var headerKey = header.Key; + var headerVal = header.Value; + if (headerKey.Contains(":")) + { + headerKey = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(headerKey)); + } + + if (headerVal.Contains(":")) + { + headerVal = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(headerVal)); + } + + base["Header" + headerIteration.ToString(numberformat)] = headerKey + ":" + headerVal; + headerIteration++; + } + } + } + } + + /// + /// Gets or sets simple structure value + /// + public bool SimpleStructure + { + get + { + object result; + if (TryGetValue("SimpleStructure", out result) && result != null) + return result.ToString().ToLower() == "true"; + return false; + } + set + { + base["SimpleStructure"] = value ? "true" : "false"; + } + } @@ -99,7 +196,6 @@ public string Encoding public JsonDataSourceConnectionStringBuilder() { ConnectionString = ""; - Headers = new Dictionary(); } /// @@ -111,76 +207,8 @@ public JsonDataSourceConnectionStringBuilder(string connectionString) : base() { ConnectionString = connectionString; - Headers = new Dictionary(); - //while (ConnectionString.Contains("Header=")) - //{ - object result; - string header = string.Empty; - string[] splittedHeader; - int headerIteration = 0; - while (TryGetValue("Header" + headerIteration.ToString(CultureInfo.InvariantCulture.NumberFormat), out result) && result != null) - { - header = (string)result; - - if (!string.IsNullOrWhiteSpace(header)) - { - splittedHeader = header.Split(':'); - - string headerKey = splittedHeader[0], headerVal = splittedHeader[1]; - - if (Regex.IsMatch(headerKey, @"^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?$")) - { - var base64str = Convert.FromBase64String(headerKey); - headerKey = System.Text.Encoding.UTF8.GetString(base64str); - } - - if (Regex.IsMatch(headerVal, @"^([A-Za-z0-9+\/]{4})*([A-Za-z0-9+\/]{3}=|[A-Za-z0-9+\/]{2}==)?$")) - { - var base64str = Convert.FromBase64String(headerVal); - headerVal = System.Text.Encoding.UTF8.GetString(base64str); - } - - Headers.Add(headerKey, headerVal); - //ConnectionString = ConnectionString.Replace(header, string.Empty); - } - - headerIteration++; - } - //} } #endregion Public Constructors - - // escape / ; " : - public override string ToString() - { - //TODO: do via stringbuilder - //string connString = $"Json={Json};JsonSchema={JsonSchema};Encoding={Encoding}"; - StringBuilder builder = new StringBuilder(); - builder.Append("Json=").Append(Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Json))) - .Append(";JsonSchema=").Append(Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(JsonSchema))) - .Append(";Encoding=").Append(Encoding); - //string connString = "Json=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(Json)) - // + ";JsonSchema=" + Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(JsonSchema)) + ";Encoding=" + Encoding; - int headerIteration = 0; - foreach (var header in Headers) - { - var headerKey = header.Key; - var headerVal = header.Value; - if (headerKey.Contains(";") || headerKey.Contains(":") || headerKey.Contains("\"") || headerKey.Contains("\'")) - { - headerKey = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(headerKey)); - } - - if (headerVal.Contains(";") || headerVal.Contains(":") || headerVal.Contains("\"") || headerVal.Contains("\'")) - { - headerVal = Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(headerVal)); - } - - builder.Append(";Header").Append(headerIteration.ToString(CultureInfo.InvariantCulture.NumberFormat)).Append("=").Append(headerKey).Append(":").Append(headerVal); - //connString += ";Header" + headerIteration + "=" + headerKey + ":" + headerVal; - } - return builder.ToString(); - } } } \ No newline at end of file diff --git a/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs b/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs index bdf63806..40f9c8cc 100644 --- a/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs +++ b/FastReport.Base/Data/JsonConnection/JsonTableDataSource.cs @@ -1,8 +1,10 @@ using FastReport.Data.ElasticSearch; using FastReport.Data.JsonConnection.JsonParser; +using FastReport.Utils; using System; using System.Collections; using System.Collections.Generic; +using System.ComponentModel; namespace FastReport.Data.JsonConnection { @@ -15,6 +17,8 @@ public class JsonTableDataSource : TableDataSource private JsonArray _json; private bool updateSchema; + private bool simpleStructure; + private string tableData; #endregion Private Fields @@ -23,6 +27,7 @@ public class JsonTableDataSource : TableDataSource /// /// Gets or sets value for force update schema on init schema /// + [Browsable(false)] public bool UpdateSchema { get @@ -34,6 +39,41 @@ public bool UpdateSchema updateSchema = value; } } + /// + /// Get or sets simplify mode for array types + /// + [Browsable(false)] + public bool SimpleStructure + { + get + { + return simpleStructure; + } + + set + { + simpleStructure = value; + } + } + + /// + [Browsable(false)] + public override string TableData + { + get + { + if (String.IsNullOrEmpty(tableData)) + { + tableData = Json.ToString(); + } + return tableData; + } + + set + { + tableData = value; + } + } #endregion Public Properties @@ -45,7 +85,14 @@ internal JsonArray Json { if (_json == null) { - _json = GetJson(Parent, this) as JsonArray; + if (StoreData && !String.IsNullOrEmpty(tableData)) + { + _json = JsonBase.FromString(tableData) as JsonArray; + } + else + { + _json = GetJson(Parent, this) as JsonArray; + } if (_json == null) _json = new JsonArray(); } @@ -101,13 +148,14 @@ public override void InitializeComponent() /// public override void InitSchema() { - if (Columns.Count == 0 || UpdateSchema) + if (Columns.Count == 0 || UpdateSchema && !StoreData) { + if (Connection is JsonDataSourceConnection) { JsonDataSourceConnection con = Connection as JsonDataSourceConnection; - InitSchema(this, con.JsonSchema); + InitSchema(this, con.JsonSchema, con.SimpleStructure); } } UpdateSchema = false; @@ -117,7 +165,8 @@ public override void InitSchema() public override void LoadData(ArrayList rows) { Json = null; - if ( rows != null) + // JSON is calculated property, no problem with null + if (rows != null && Json != null) { rows.Clear(); int count = Json.Count; @@ -136,13 +185,25 @@ internal static object GetJsonBaseByColumn(Base parentColumn, Column column) { if (parentColumn is JsonTableDataSource) { - switch (column.PropName) + JsonTableDataSource jsonTableDataSource = parentColumn as JsonTableDataSource; + if (jsonTableDataSource.SimpleStructure) { - case "item": - return (parentColumn as JsonTableDataSource).Json[(parentColumn as JsonTableDataSource).CurrentIndex]; + if (!String.IsNullOrEmpty(column.PropName)) + { + var obj = (parentColumn as JsonTableDataSource).Json[(parentColumn as JsonTableDataSource).CurrentIndex]; + return (obj as JsonBase)[column.PropName]; + } + } + else + { + switch (column.PropName) + { + case "item": + return (parentColumn as JsonTableDataSource).Json[(parentColumn as JsonTableDataSource).CurrentIndex]; + } + JsonTableDataSource source = column as JsonTableDataSource; + return source.Json; } - JsonTableDataSource source = column as JsonTableDataSource; - return source.Json; } if (parentColumn is Column && !String.IsNullOrEmpty(column.PropName)) { @@ -175,7 +236,7 @@ internal static object GetValueByColumn(Base parentColumn, Column column) return json; } - internal static void InitSchema(Column table, JsonSchema schema) + internal static void InitSchema(Column table, JsonSchema schema, bool simpleStructure) { List saveColumns = new List(); switch (schema.Type) @@ -191,7 +252,7 @@ internal static void InitSchema(Column table, JsonSchema schema) c.PropName = kv.Key; c.DataType = kv.Value.DataType; c = UpdateColumn(table, c, saveColumns); - InitSchema(c, kv.Value); + InitSchema(c, kv.Value, simpleStructure); } else if (kv.Value.Type == "array") { @@ -201,7 +262,9 @@ internal static void InitSchema(Column table, JsonSchema schema) c.PropName = kv.Key; c.DataType = kv.Value.DataType; c = UpdateColumn(table, c, saveColumns); - InitSchema(c, kv.Value); + + InitSchema(c, kv.Value, simpleStructure); + } else { @@ -218,6 +281,26 @@ internal static void InitSchema(Column table, JsonSchema schema) case "array": JsonSchema items = schema.Items; + + bool simpleArray = false; + + if (table is JsonTableDataSource) + { + JsonTableDataSource jsonTableDataSource = table as JsonTableDataSource; + simpleArray = jsonTableDataSource.SimpleStructure = + simpleStructure & items.Type == "object"; + } + + if (simpleArray) + { + // remake schema in simplify mode + InitSchema(table, items, simpleStructure); + // and return, no need to clear column data + // in this case this method has no control to columns + return; + } + + { Column c = new Column(); c.Name = "index"; @@ -227,6 +310,8 @@ internal static void InitSchema(Column table, JsonSchema schema) UpdateColumn(table, c, saveColumns); } + + { Column c; bool iSchema = false; @@ -254,7 +339,7 @@ internal static void InitSchema(Column table, JsonSchema schema) c = UpdateColumn(table, c, saveColumns); if (iSchema) - InitSchema(c, items); + InitSchema(c, items, simpleStructure); } { @@ -265,6 +350,7 @@ internal static void InitSchema(Column table, JsonSchema schema) c.DataType = typeof(JsonBase); UpdateColumn(table, c, saveColumns); } + break; } @@ -280,7 +366,7 @@ internal static void InitSchema(Column table, JsonSchema schema) internal object GetJson(Base parentColumn, Column column) { - if(parentColumn is ESDataSourceConnection) + if (parentColumn is ESDataSourceConnection) parentColumn = (parentColumn as ESDataSourceConnection).GetParentJTDSByName(column.Name); if (parentColumn is JsonDataSourceConnection) { @@ -292,7 +378,19 @@ internal object GetJson(Base parentColumn, Column column) if (parentColumn.Parent is ESDataSourceConnection) parentColumn.Parent = (parentColumn.Parent as ESDataSourceConnection).GetParentJTDSByName(parentColumn.Name); JsonTableDataSource source = parentColumn as JsonTableDataSource; - return source.Json[source.CurrentRowNo] as object; + + if (source.SimpleStructure) + { + object parentJson = source.Json[source.CurrentRowNo]; + if (parentJson is JsonBase && !String.IsNullOrEmpty(column.PropName)) + { + return (parentJson as JsonBase)[column.PropName]; + } + } + else + { + return source.Json[source.CurrentRowNo] as object; + } } else if (parentColumn is Column) { @@ -353,5 +451,17 @@ private static Column UpdateColumn(Column table, Column c, List list) } #endregion Private Methods + + + /// + public override void Serialize(FRWriter writer) + { + base.Serialize(writer); + + if (SimpleStructure) + { + writer.WriteBool("SimpleStructure", SimpleStructure); + } + } } } \ No newline at end of file diff --git a/FastReport.Base/Data/TableDataSource.cs b/FastReport.Base/Data/TableDataSource.cs index 86c969ab..5ab3d0f1 100644 --- a/FastReport.Base/Data/TableDataSource.cs +++ b/FastReport.Base/Data/TableDataSource.cs @@ -126,7 +126,7 @@ public bool StoreData /// This property is for internal use only. /// [Browsable(false)] - public string TableData + public virtual string TableData { get { diff --git a/FastReport.Base/Export/Html/HTMLExportDraw.cs b/FastReport.Base/Export/Html/HTMLExportDraw.cs index 15c65425..67126011 100644 --- a/FastReport.Base/Export/Html/HTMLExportDraw.cs +++ b/FastReport.Base/Export/Html/HTMLExportDraw.cs @@ -65,8 +65,10 @@ private string HTMLBorderWidthPx(BorderLine line) float width; if (line.Style == LineStyle.Double) width = line.Width * 3 * Zoom; - else + else if (layers) width = line.Width * Zoom; + else + width = line.Width; return ExportUtils.FloatToString(width) + "px;"; } diff --git a/FastReport.Base/Export/Html/HTMLExportLayers.cs b/FastReport.Base/Export/Html/HTMLExportLayers.cs index c9cfdddd..7423f12e 100644 --- a/FastReport.Base/Export/Html/HTMLExportLayers.cs +++ b/FastReport.Base/Export/Html/HTMLExportLayers.cs @@ -565,19 +565,19 @@ private string GetLayerPicture(ReportComponentBase obj, out float Width, out flo BorderLines oldLines = obj.Border.Lines; obj.Border.Lines = BorderLines.None; - obj.Draw(new FRPaintEventArgs(g, Zoom + zoom - 1, Zoom + zoom - 1, Report.GraphicCache)); + obj.Draw(new FRPaintEventArgs(g, Zoom * zoom, Zoom * zoom, Report.GraphicCache)); obj.Border.Lines = oldLines; } if(Width > 0 && Height > 0) using (Bitmap b = new Bitmap( - (int)(Math.Abs(Math.Round(Width * Zoom * zoom))), - (int)(Math.Abs(Math.Round(Height * Zoom * zoom))) + (int)(Math.Abs(Math.Round(Width * Zoom))), + (int)(Math.Abs(Math.Round(Height * Zoom))) )) { using (Graphics gr = Graphics.FromImage(b)) { gr.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; - gr.DrawImage(image, 0, 0, (int)Width * Zoom * zoom, (int)Height * Zoom * zoom); + gr.DrawImage(image, 0, 0, (int)Width * Zoom, (int)Height * Zoom); } if (FPictureFormat == System.Drawing.Imaging.ImageFormat.Jpeg) @@ -612,6 +612,7 @@ private string GetLayerPicture(ReportComponentBase obj, out float Width, out flo } } #else + hash = Crypter.ComputeHash(PictureStream); PictureStream.Position = 0; #endif diff --git a/FastReport.Base/Import/DevExpress/DevExpressImport.cs b/FastReport.Base/Import/DevExpress/DevExpressImport.cs index 46a84d01..1a42c0f2 100644 --- a/FastReport.Base/Import/DevExpress/DevExpressImport.cs +++ b/FastReport.Base/Import/DevExpress/DevExpressImport.cs @@ -1011,11 +1011,24 @@ private void LoadReport() #region Public Methods + /// public override void LoadReport(Report report, string filename) + { + using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + LoadReport(report, fs); + } + } + + /// + public override void LoadReport(Report report, Stream content) { Report = report; Report.Clear(); - devText = File.ReadAllText(filename); + using(var sr = new StreamReader(content)) + { + devText = sr.ReadToEnd(); + } try { devDoc = new System.Xml.XmlDocument(); diff --git a/FastReport.Base/Import/ImportBase.cs b/FastReport.Base/Import/ImportBase.cs index 4c1467e5..f9aef857 100644 --- a/FastReport.Base/Import/ImportBase.cs +++ b/FastReport.Base/Import/ImportBase.cs @@ -1,3 +1,5 @@ +using System.IO; + namespace FastReport.Import { /// @@ -57,6 +59,16 @@ public virtual void LoadReport(Report report, string filename) report.Clear(); } + /// + /// Loads the specified file into specified report from stream. + /// + /// Report object + /// File stream + public virtual void LoadReport(Report report, Stream content) + { + report.Clear(); + } + #endregion // Public Methods } } diff --git a/FastReport.Base/Import/ListAndLabel/ListAndLabelImport.cs b/FastReport.Base/Import/ListAndLabel/ListAndLabelImport.cs index a2172f2d..29229eb4 100644 --- a/FastReport.Base/Import/ListAndLabel/ListAndLabelImport.cs +++ b/FastReport.Base/Import/ListAndLabel/ListAndLabelImport.cs @@ -413,7 +413,19 @@ private void LoadReport() /// public override void LoadReport(Report report, string filename) { - textLL = File.ReadAllText(filename); + using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + LoadReport(report, fs); + } + } + + /// + public override void LoadReport(Report report, Stream content) + { + using(var sr = new StreamReader(content)) + { + textLL = sr.ReadToEnd(); + } isListAndLabelReport = CheckIsListAndLabelReport(); if (isListAndLabelReport) { diff --git a/FastReport.Base/Import/RDL/RDLImport.cs b/FastReport.Base/Import/RDL/RDLImport.cs index f2c29ac2..d162809f 100644 --- a/FastReport.Base/Import/RDL/RDLImport.cs +++ b/FastReport.Base/Import/RDL/RDLImport.cs @@ -926,11 +926,19 @@ private void LoadReport(XmlNode reportNode) public override void LoadReport(Report report, string filename) { this.filename = filename; + using (FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read)) + { + LoadReport(report, fs); + } + } + /// + public override void LoadReport(Report report, Stream content) + { Report = report; Report.Clear(); - XmlDocument doc = new XmlDocument(); - doc.Load(filename); - reportNode = doc.LastChild; + XmlDocument document = new XmlDocument(); + document.Load(content); + reportNode = document.LastChild; defaultFontFamily = ""; page = null; LoadReport(reportNode); diff --git a/FastReport.Base/PictureObjectBase.cs b/FastReport.Base/PictureObjectBase.cs index 2993530d..7c57e471 100644 --- a/FastReport.Base/PictureObjectBase.cs +++ b/FastReport.Base/PictureObjectBase.cs @@ -820,7 +820,7 @@ protected void UpdateAutoSize() { if (ImageWidth == 0 || ImageHeight == 0) { - if (IsRunning) + if (IsRunning && !IsPrinting) { Width = 0; Height = 0; diff --git a/FastReport.Base/ReportComponentBase.cs b/FastReport.Base/ReportComponentBase.cs index fbf864ea..b55624a2 100644 --- a/FastReport.Base/ReportComponentBase.cs +++ b/FastReport.Base/ReportComponentBase.cs @@ -792,6 +792,29 @@ public virtual bool IsVisible(FRPaintEventArgs e) return e.Graphics.IsVisible(objRect); } + /// + /// Validate this object. + /// + /// List of errors + public virtual List Validate() + { + List listError = new List(); + + if (IsIntersectingWithOtherObject && !(Parent is ReportComponentBase && !Validator.RectContainInOtherRect((Parent as ReportComponentBase).AbsBounds, this.AbsBounds))) + listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Warning, Res.Get("Messages,Validator,IntersectedObjects"), this)); + + if (Height <= 0 || Width <= 0) + listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,IncorrectSize"), this)); + + if (Name == "") + listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,UnnamedObject"), this)); + + if (Parent is ReportComponentBase && !Validator.RectContainInOtherRect((Parent as ReportComponentBase).AbsBounds, this.AbsBounds)) + listError.Add(new ValidationError(Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,OutOfBounds"), this)); + + return listError; + } + /// public override void Serialize(FRWriter writer) { diff --git a/FastReport.Base/Utils/Validator.cs b/FastReport.Base/Utils/Validator.cs index c1f978a3..d243003d 100644 --- a/FastReport.Base/Utils/Validator.cs +++ b/FastReport.Base/Utils/Validator.cs @@ -1,8 +1,33 @@ using System; +using System.Collections.Generic; using System.Drawing; +using System.Linq; namespace FastReport.Utils { + + public struct ValidationError + { + public enum ErrorLevel + { + Warning, + Error + } + + public string Name; + public ErrorLevel Level; + public string Message; + public ReportComponentBase Object; + + public ValidationError(string name, ErrorLevel level, string message, ReportComponentBase obj) + { + this.Name = name; + this.Level = level; + this.Message = message; + this.Object = obj; + } + } + /// /// Contains methods used for validation of report. /// @@ -43,9 +68,57 @@ static public bool ValidateIntersectionAllObjects(BandBase band) return result; } + /// + /// Check child rectangle on contains in parent rectangle. + /// + /// + /// + /// + static public bool RectContainInOtherRect(RectangleF parent, RectangleF child) + { + return parent.Contains(GetReducedRect(child)); + } + private static RectangleF GetReducedRect(RectangleF rect) { return new RectangleF(rect.X + 0.01f, rect.Y + 0.01f, rect.Width - 0.02f, rect.Height - 0.02f); } + + static public List ValidateReport(Report report) + { + if (report == null) + return null; + List listError = new List(); + + foreach (PageBase page in report.Pages) + { + foreach (Base c in page.AllObjects) + { + if (c is ReportComponentBase) + listError.AddRange((c as ReportComponentBase).Validate()); + + if (c is BandBase) + ValidateIntersectionAllObjects(c as BandBase); + } + } + + bool duplicateName; + for (int i = 0; i < report.AllObjects.Count - 1; i++) + { + duplicateName = false; + for (int j = i + 1; j < report.AllObjects.Count; j++) + { + if (report.AllObjects[j] is ReportComponentBase && report.AllObjects[i].Name == report.AllObjects[j].Name) + { + listError.Add(new ValidationError(report.AllObjects[j].Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,DuplicateName"), (ReportComponentBase)report.AllObjects[j])); + duplicateName = true; + } + } + if(report.AllObjects[i] is ReportComponentBase && duplicateName) + listError.Add(new ValidationError(report.AllObjects[i].Name, ValidationError.ErrorLevel.Error, Res.Get("Messages,Validator,DuplicateName"), (ReportComponentBase)report.AllObjects[i])); + } + + return listError.Distinct().ToList(); + } } } \ No newline at end of file diff --git a/FastReport/Resources/en.xml b/FastReport/Resources/en.xml index 9c343672..38b238f4 100644 --- a/FastReport/Resources/en.xml +++ b/FastReport/Resources/en.xml @@ -69,6 +69,13 @@ + + + + + + + @@ -491,6 +498,11 @@ + + + + + @@ -2276,6 +2288,7 @@ + diff --git a/Localization/Russian.frl b/Localization/Russian.frl index c7def221..9cc95798 100644 --- a/Localization/Russian.frl +++ b/Localization/Russian.frl @@ -69,6 +69,13 @@ + + + + + + + @@ -473,9 +480,9 @@ - - - + + + @@ -486,6 +493,11 @@ + + + + + @@ -2062,6 +2074,7 @@ +