FastReport

Форк
0
2870 строк · 99.2 Кб
1
using FastReport.Code;
2
using FastReport.CrossView;
3
using FastReport.Data;
4
using FastReport.Dialog;
5
using FastReport.Engine;
6
using FastReport.Export;
7
using FastReport.Utils;
8
using System;
9
using System.Collections;
10
using System.Collections.Generic;
11
using System.ComponentModel;
12
using System.Data;
13
using System.Diagnostics;
14
using System.Drawing;
15
using System.Drawing.Text;
16
using System.IO;
17
using System.Linq;
18
using System.Linq.Expressions;
19
using System.Security;
20
using System.Text;
21
using System.Threading;
22
using System.Threading.Tasks;
23
using System.Windows.Forms;
24

25
namespace FastReport
26
{
27
    /// <summary>
28
    /// Specifies the language of the report's script.
29
    /// </summary>
30
    public enum Language
31
    {
32
        /// <summary>
33
        /// The C# language.
34
        /// </summary>
35
        CSharp,
36

37
        /// <summary>
38
        /// The VisualBasic.Net language.
39
        /// </summary>
40
        Vb
41
    }
42

43
    /// <summary>
44
    /// Specifies the quality of text rendering.
45
    /// </summary>
46
    public enum TextQuality
47
    {
48
        /// <summary>
49
        /// The default text quality, depends on system settings.
50
        /// </summary>
51
        Default,
52

53
        /// <summary>
54
        /// The regular quality.
55
        /// </summary>
56
        Regular,
57

58
        /// <summary>
59
        /// The "ClearType" quality.
60
        /// </summary>
61
        ClearType,
62

63
        /// <summary>
64
        /// The AntiAlias quality. This mode may be used to produce the WYSIWYG text.
65
        /// </summary>
66
        AntiAlias,
67

68
        /// <summary>
69
        /// The "SingleBitPerPixel" quality.
70
        /// </summary>
71
        SingleBPP,
72

73

74
        /// <summary>
75
        /// The "SingleBitPerPixelGridFit" quality.
76
        /// </summary>
77
        SingleBPPGridFit
78
    }
79

80
    /// <summary>
81
    /// Specifies the report operation.
82
    /// </summary>
83
    public enum ReportOperation
84
    {
85
        /// <summary>
86
        /// Specifies no operation.
87
        /// </summary>
88
        None,
89

90
        /// <summary>
91
        /// The report is running.
92
        /// </summary>
93
        Running,
94

95
        /// <summary>
96
        /// The report is printing.
97
        /// </summary>
98
        Printing,
99

100
        /// <summary>
101
        /// The report is exporting.
102
        /// </summary>
103
        Exporting
104
    }
105

106
    /// <summary>
107
    /// Specifies the page range to print/export.
108
    /// </summary>
109
    public enum PageRange
110
    {
111
        /// <summary>
112
        /// Print all pages.
113
        /// </summary>
114
        All,
115

116
        /// <summary>
117
        /// Print current page.
118
        /// </summary>
119
        Current,
120

121
        /// <summary>
122
        /// Print pages specified in the <b>PageNumbers</b> property of the <b>PrintSettings</b>.
123
        /// </summary>
124
        PageNumbers
125
    }
126

127
    /// <summary>
128
    /// Represents a report object.
129
    /// </summary>
130
    /// <remarks>
131
    /// <para>The instance of this class contains a report. Here are some common
132
    /// actions that can be performed with this object:</para>
133
    /// <list type="bullet">
134
    ///   <item>
135
    ///     <description>To load a report, use the <see cref="Load(string)"/>
136
    ///     method or call static <see cref="FromFile"/> method. </description>
137
    ///   </item>
138
    ///   <item>
139
    ///     <description>To save a report, call the <see cref="Save(string)"/> method.</description>
140
    ///   </item>
141
    ///   <item>
142
    ///     <description>To register application dataset for use it in a report, call one of the
143
    ///     <b>RegisterData</b> methods.</description>
144
    ///   </item>
145
    ///   <item>
146
    ///     <description>To pass some parameter to a report, use the
147
    ///     <see cref="SetParameterValue"/> method.</description>
148
    ///   </item>
149
    ///   <item>
150
    ///     <description>To design a report, call the <see cref="Design()"/> method.</description>
151
    ///   </item>
152
    ///   <item>
153
    ///     <description>To run a report and preview it, call the <see cref="Show()"/> method.
154
    ///     Another way is to call the <see cref="Prepare()"/> method, then call the
155
    ///     <see cref="ShowPrepared()"/> method.</description>
156
    ///   </item>
157
    ///   <item>
158
    ///     <description>To run a report and print it, call the <see cref="Print"/> method.
159
    ///     Another way is to call the <see cref="Prepare()"/> method, then call the
160
    ///     <see cref="PrintPrepared()"/> method.</description>
161
    ///   </item>
162
    ///   <item>
163
    ///     <description>To load/save prepared report, use one of the <b>LoadPrepared</b> and
164
    ///     <b>SavePrepared</b> methods.</description>
165
    ///   </item>
166
    ///   <item>
167
    ///     <description>To set up some global properties, use the <see cref="Config"/> static class
168
    ///     or <see cref="EnvironmentSettings"/> component that you can use in the Visual Studio IDE.
169
    ///     </description>
170
    ///   </item>
171
    /// </list>
172
    /// <para/>The report consists of one or several report pages (pages of the
173
    /// <see cref="ReportPage"/> type) and/or dialog forms (pages of the <see cref="DialogPage"/> type).
174
    /// They are stored in the <see cref="Pages"/> collection. In turn, each page may contain report
175
    /// objects. See the example below how to create a simple report in code.
176
    /// </remarks>
177
    /// <example>This example shows how to create a report instance, load it from a file,
178
    /// register the application data, run and preview.
179
    /// <code>
180
    /// Report report = new Report();
181
    /// report.Load("reportfile.frx");
182
    /// report.RegisterData(application_dataset);
183
    /// report.Show();
184
    /// </code>
185
    /// <para/>This example shows how to create simple report in code.
186
    /// <code>
187
    /// Report report = new Report();
188
    /// // create the report page
189
    /// ReportPage page = new ReportPage();
190
    /// page.Name = "ReportPage1";
191
    /// // set paper width and height. Note: these properties are measured in millimeters.
192
    /// page.PaperWidth = 210;
193
    /// page.PaperHeight = 297;
194
    /// // add a page to the report
195
    /// report.Pages.Add(page);
196
    /// // create report title
197
    /// page.ReportTitle = new ReportTitleBand();
198
    /// page.ReportTitle.Name = "ReportTitle1";
199
    /// page.ReportTitle.Height = Units.Millimeters * 10;
200
    /// // create Text object and put it to the title
201
    /// TextObject text = new TextObject();
202
    /// text.Name = "Text1";
203
    /// text.Bounds = new RectangleF(0, 0, Units.Millimeters * 100, Units.Millimeters * 5);
204
    /// page.ReportTitle.Objects.Add(text);
205
    /// // create data band
206
    /// DataBand data = new DataBand();
207
    /// data.Name = "Data1";
208
    /// data.Height = Units.Millimeters * 10;
209
    /// // add data band to a page
210
    /// page.Bands.Add(data);
211
    /// </code>
212
    /// </example>
213

214
    public partial class Report : Base, IParent, ISupportInitialize
215
    {
216
        #region Fields
217

218
        private PageCollection pages;
219
        private Dictionary dictionary;
220
        private ReportInfo reportInfo;
221
        private string baseReport;
222
        private Report baseReportObject;
223
        private string baseReportAbsolutePath;
224
        private string fileName;
225
        private string scriptText;
226
        private Language scriptLanguage;
227
        private bool compressed;
228
        private bool useFileCache;
229
        private TextQuality textQuality;
230
        private bool smoothGraphics;
231
        private string password;
232
        private bool convertNulls;
233
        private bool doublePass;
234
        private bool autoFillDataSet;
235
        private int initialPageNumber;
236
        private int maxPages;
237
        private string startReportEvent;
238
        private string finishReportEvent;
239
        private StyleCollection styles;
240
        private CodeHelperBase codeHelper;
241
        private GraphicCache graphicCache;
242
        private string[] referencedAssemblies;
243
        private Hashtable cachedDataItems;
244
        private AssemblyCollection assemblies;
245
        private FastReport.Preview.PreparedPages preparedPages;
246
        private ReportEngine engine;
247
        private bool aborted;
248
        private Bitmap measureBitmap;
249
        private IGraphics measureGraphics;
250
        private bool storeInResources;
251
        private PermissionSet scriptRestrictions;
252
        private ReportOperation operation;
253
        private bool needCompile;
254
        private bool scriptChanged = false;
255
        private bool needRefresh;
256
        private bool isParameterChanged = false;
257
        private bool initializing;
258
        private object initializeData;
259
        private string initializeDataName;
260
        private object tag;
261
        private bool isLoadPrepared = false;
262

263
        #endregion Fields
264

265
        #region Properties
266

267
        /// <summary>
268
        /// Occurs when calc execution is started.
269
        /// </summary>
270
        public event CustomCalcEventHandler CustomCalc;
271

272
        /// <summary>
273
        /// Occurs when report is inherited and trying to load a base report.
274
        /// </summary>
275
        /// <remarks>
276
        /// Typical use of this event is to load the base report from a database instead of a file.
277
        /// </remarks>
278
        public event CustomLoadEventHandler LoadBaseReport;
279

280
        /// <summary>
281
        /// Occurs when report execution is started.
282
        /// </summary>
283
        public event EventHandler StartReport;
284

285
        /// <summary>
286
        /// Occurs when report execution is finished.
287
        /// </summary>
288
        public event EventHandler FinishReport;
289

290
        /// <summary>
291
        /// Occurs before export to set custom export parameters.
292
        /// </summary>
293
        public event EventHandler<ExportParametersEventArgs> ExportParameters;
294

295
        /// <summary>
296
        /// Gets the pages contained in this report.
297
        /// </summary>
298
        /// <remarks>
299
        /// This property contains pages of all types (report and dialog). Use the <b>is/as</b> operators
300
        /// if you want to work with pages of <b>ReportPage</b> type.
301
        /// </remarks>
302
        /// <example>The following code demonstrates how to access the first report page:
303
        /// <code>
304
        /// ReportPage page1 = report1.Pages[0] as ReportPage;
305
        /// </code>
306
        /// </example>
307
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
308
        public PageCollection Pages
309
        {
310
            get { return pages; }
311
        }
312

313
        /// <summary>
314
        /// Gets the report's data.
315
        /// </summary>
316
        /// <remarks>
317
        /// The dictionary contains all data items such as connections, data sources, parameters,
318
        /// system variables.
319
        /// </remarks>
320
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
321
        public Dictionary Dictionary
322
        {
323
            get { return dictionary; }
324
            set
325
            {
326
                SetProp(dictionary, value);
327
                dictionary = value;
328
            }
329
        }
330

331
        /// <summary>
332
        /// Gets the collection of report parameters.
333
        /// </summary>
334
        /// <remarks>
335
        /// <para>Parameters are displayed in the "Data" window under the "Parameters" node.</para>
336
        /// <para>Typical use of parameters is to pass some static data from the application to the report.
337
        /// You can print such data, use it in the data row filter, script etc. </para>
338
        /// <para>Another way to use parameters is to define some reusable piece of code, for example,
339
        /// to define an expression that will return the concatenation of first and second employee name.
340
        /// In this case, you set the parameter's <b>Expression</b> property to something like this:
341
        /// [Employees.FirstName] + " " + [Employees.LastName]. Now this parameter may be used in the report
342
        /// to print full employee name. Each time you access such parameter, it will calculate the expression
343
        /// and return its value. </para>
344
        /// <para>You can create nested parameters. To do this, add the new <b>Parameter</b> to the
345
        /// <b>Parameters</b> collection of the root parameter. To access the nested parameter, you may use the
346
        /// <see cref="GetParameter"/> method.</para>
347
        /// <para>To get or set the parameter's value, use the <see cref="GetParameterValue"/> and
348
        /// <see cref="SetParameterValue"/> methods. To set the parameter's expression, use the
349
        /// <see cref="GetParameter"/> method that returns a <b>Parameter</b> object and set its
350
        /// <b>Expression</b> property.</para>
351
        /// </remarks>
352
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
353
        public ParameterCollection Parameters
354
        {
355
            get { return dictionary.Parameters; }
356
        }
357

358
        /// <summary>
359
        /// Gets or sets the report information such as report name, author, description etc.
360
        /// </summary>
361
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
362
        [SRCategory("Design")]
363
        public ReportInfo ReportInfo
364
        {
365
            get { return reportInfo; }
366
            set { reportInfo = value; }
367
        }
368

369
        /// <summary>
370
        /// Gets or sets the base report file name.
371
        /// </summary>
372
        /// <remarks>
373
        /// This property contains the name of a report file this report is inherited from.
374
        /// <b>Note:</b> setting this property to non-empty value will clear the report and
375
        /// load the base file into it.
376
        /// </remarks>
377
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
378
        public string BaseReport
379
        {
380
            get { return baseReport; }
381
            set { SetBaseReport(value); }
382
        }
383

384
        /// <summary>
385
        /// Gets a value indicating whether Report is prepared
386
        /// </summary>
387
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
388
        public bool IsPrepared
389
        {
390
            get { return !isParameterChanged && PreparedPages != null && PreparedPages.Count != 0; }
391
        }
392
        /// <summary>
393
        /// Gets or sets the absolute path to the parent report.
394
        /// </summary>
395
        /// <remarks>
396
        /// This property contains the absolute path to the parent report.
397
        /// </remarks>
398
        [Browsable(true), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
399
        public string BaseReportAbsolutePath
400
        {
401
            get { return baseReportAbsolutePath; }
402
            set { baseReportAbsolutePath = value; }
403
        }
404

405
        /// <summary>
406
        /// Gets or sets the name of a file the report was loaded from.
407
        /// </summary>
408
        /// <remarks>
409
        /// This property is used to support the FastReport.Net infrastructure;
410
        /// typically you don't need to use it.
411
        /// </remarks>
412
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
413
        public string FileName
414
        {
415
            get { return fileName; }
416
            set { fileName = value; }
417
        }
418

419
        /// <summary>
420
        /// Gets or sets the report script.
421
        /// </summary>
422
        /// <remarks>
423
        /// <para>The script contains the <b>ReportScript</b> class that contains all report objects'
424
        /// event handlers and own items such as private fields, properties, methods etc. The script
425
        /// contains only items written by you. Unlike other report generators, the script does not
426
        /// contain report objects declarations, initialization code. It is added automatically when
427
        /// you run the report.</para>
428
        /// <para>By default this property contains an empty script text. You may see it in the designer
429
        /// when you switch to the Code window.</para>
430
        /// <para>If you set this property programmatically, you have to declare the <b>FastReport</b>
431
        /// namespace and the <b>ReportScript</b> class in it. Do not declare report items (such as bands,
432
        /// objects, etc) in the <b>ReportScript</b> class: the report engine does this automatically when
433
        /// you run the report.</para>
434
        /// <para><b>Security note:</b> since the report script is compiled into .NET assembly, it allows
435
        /// you to do ANYTHING. For example, you may create a script that will read/write files from/to a disk.
436
        /// To restrict such operations, use the <see cref="ScriptRestrictions"/> property.</para>
437
        /// </remarks>
438
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
439
        public string ScriptText
440
        {
441
            get { return scriptText; }
442
            set
443
            {
444
                scriptText = value;
445
                scriptChanged = scriptText != codeHelper.EmptyScript();
446
            }
447
        }
448

449
        /// <summary>
450
        /// Gets or sets the script language of this report.
451
        /// </summary>
452
        /// <remarks>
453
        /// Note: changing this property will reset the report script to default empty script.
454
        /// </remarks>
455
        [DefaultValue(Language.CSharp)]
456
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
457
        [SRCategory("Script")]
458
        public Language ScriptLanguage
459
        {
460
            get { return scriptLanguage; }
461
            set
462
            {
463
                bool needClear = scriptLanguage != value;
464
                scriptLanguage = value;
465
                if (scriptLanguage == Language.CSharp)
466
                    codeHelper = new CsCodeHelper(this);
467
                else
468
                    codeHelper = new VbCodeHelper(this);
469
                if (needClear)
470
                {
471
                    scriptText = codeHelper.EmptyScript();
472
                    scriptChanged = false;
473
                }
474
            }
475
        }
476

477
        /// <summary>
478
        /// Gets or sets a value indicating whether the null DB value must be converted to zero, false or
479
        /// empty string depending on the data column type.
480
        /// </summary>
481
        /// <remarks>
482
        /// This property is <b>true</b> by default. If you set it to <b>false</b>, you should check
483
        /// the DB value before you do something with it (for example, typecast it to any type, use it
484
        /// in a expression etc.)
485
        /// </remarks>
486
        [DefaultValue(true)]
487
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
488
        [SRCategory("Engine")]
489
        public bool ConvertNulls
490
        {
491
            get { return convertNulls; }
492
            set { convertNulls = value; }
493
        }
494

495
        /// <summary>
496
        /// Gets or sets a value that specifies whether the report engine should perform the second pass.
497
        /// </summary>
498
        /// <remarks>
499
        /// <para>Typically the second pass is necessary to print the number of total pages. It also
500
        /// may be used to perform some calculations on the first pass and print its results on the
501
        /// second pass.</para>
502
        /// <para>Use the <b>Engine.FirstPass</b>, <b>Engine.FinalPass</b> properties to determine which
503
        /// pass the engine is performing now.</para>
504
        /// </remarks>
505
        [DefaultValue(false)]
506
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
507
        [SRCategory("Engine")]
508
        public bool DoublePass
509
        {
510
            get { return doublePass; }
511
            set { doublePass = value; }
512
        }
513

514
        /// <summary>
515
        /// Gets or sets a value that specifies whether to compress the report file.
516
        /// </summary>
517
        /// <remarks>
518
        /// The report file is compressed using the Gzip algorithm. So you can open the
519
        /// compressed report in any zip-compatible archiver.
520
        /// </remarks>
521
        [DefaultValue(false)]
522
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
523
        [SRCategory("Misc")]
524
        public bool Compressed
525
        {
526
            get { return compressed; }
527
            set { compressed = value; }
528
        }
529

530
        /// <summary>
531
        /// Returns a bool value depending on the .frx or .fpx report was loaded
532
        /// </summary>
533
        public bool IsLoadPrepared
534
        {
535
            get => isLoadPrepared;
536
        }
537

538
        /// <summary>
539
        /// Gets or sets a value that specifies whether to use the file cache rather than memory
540
        /// to store the prepared report pages.
541
        /// </summary>
542
        [DefaultValue(false)]
543
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
544
        [SRCategory("Engine")]
545
        public bool UseFileCache
546
        {
547
            get { return useFileCache; }
548
            set { useFileCache = value; }
549
        }
550

551
        /// <summary>
552
        /// Gets or sets a value that specifies the quality of text rendering.
553
        /// </summary>
554
        /// <remarks>
555
        /// <b>Note:</b> the default property value is <b>TextQuality.Default</b>. That means the report
556
        /// may look different depending on OS settings. This property does not affect the printout.
557
        /// </remarks>
558
        [DefaultValue(TextQuality.Default)]
559
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
560
        [SRCategory("Misc")]
561
        public TextQuality TextQuality
562
        {
563
            get { return textQuality; }
564
            set { textQuality = value; }
565
        }
566

567
        /// <summary>
568
        /// Gets or sets a value that specifies if the graphic objects such as bitmaps
569
        /// and shapes should be displayed smoothly.
570
        /// </summary>
571
        [DefaultValue(false)]
572
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
573
        [SRCategory("Misc")]
574
        public bool SmoothGraphics
575
        {
576
            get { return smoothGraphics; }
577
            set { smoothGraphics = value; }
578
        }
579

580
        /// <summary>
581
        /// Gets or sets the report password.
582
        /// </summary>
583
        /// <remarks>
584
        /// <para>When you try to load the password-protected report, you will be asked
585
        /// for a password. You also may specify the password in this property before loading
586
        /// the report. In this case the report will load silently.</para>
587
        /// <para>Password-protected report file is crypted using Rijndael algorithm.
588
        /// Do not forget your password! It will be hard or even impossible to open
589
        /// the protected file in this case.</para>
590
        /// </remarks>
591
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
592
        public string Password
593
        {
594
            get { return password; }
595
            set { password = value; }
596
        }
597

598
        /// <summary>
599
        /// Gets or sets a value indicating whether it is necessary to automatically fill
600
        /// DataSet registered with <b>RegisterData</b> call.
601
        /// </summary>
602
        /// <remarks>
603
        /// If this property is <b>true</b> (by default), FastReport will automatically fill
604
        /// the DataSet with data when you trying to run a report. Set it to <b>false</b> if
605
        /// you want to fill the DataSet by yourself.
606
        /// </remarks>
607
        [DefaultValue(true)]
608
        [SRCategory("Misc")]
609
        public bool AutoFillDataSet
610
        {
611
            get { return autoFillDataSet; }
612
            set { autoFillDataSet = value; }
613
        }
614

615
        /// <summary>
616
        /// Gets or sets the maximum number of generated pages in a prepared report.
617
        /// </summary>
618
        /// <remarks>
619
        /// Use this property to limit the number of pages in a prepared report.
620
        /// </remarks>
621
        [DefaultValue(0)]
622
        [SRCategory("Misc")]
623
        public int MaxPages
624
        {
625
            get { return maxPages; }
626
            set { maxPages = value; }
627
        }
628

629
        /// <summary>
630
        /// Gets or sets the collection of styles used in this report.
631
        /// </summary>
632
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
633
        [SRCategory("Misc")]
634
        public StyleCollection Styles
635
        {
636
            get { return styles; }
637
            set { styles = value; }
638
        }
639

640
        /// <summary>
641
        /// Gets or sets an array of assembly names that will be used to compile the report script.
642
        /// </summary>
643
        /// <remarks>
644
        /// By default this property contains the following assemblies: "System.dll", "System.Drawing.dll",
645
        /// "System.Windows.Forms.dll", "System.Data.dll", "System.Xml.dll". If your script uses some types
646
        /// from another assemblies, you have to add them to this property.
647
        /// </remarks>
648
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
649
        [SRCategory("Script")]
650
        public string[] ReferencedAssemblies
651
        {
652
            get { return referencedAssemblies; }
653
            set
654
            {
655
                if (value != null)
656
                {
657
                    // fix for old reports with "System.Windows.Forms.DataVisualization" in referenced assemblies 
658
                    for (int i = 0; i < value.Length; i++)
659
                    {
660
                        value[i] = value[i].Replace("System.Windows.Forms.DataVisualization", "FastReport.DataVisualization");
661
                    }
662
                }
663
                referencedAssemblies = value;
664
            }
665
        }
666

667
        /// <summary>
668
        /// Gets or sets a script event name that will be fired when the report starts.
669
        /// </summary>
670
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
671
        [SRCategory("Build")]
672
        public string StartReportEvent
673
        {
674
            get { return startReportEvent; }
675
            set { startReportEvent = value; }
676
        }
677

678
        /// <summary>
679
        /// Gets or sets a script event name that will be fired when the report is finished.
680
        /// </summary>
681
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
682
        [SRCategory("Build")]
683
        public string FinishReportEvent
684
        {
685
            get { return finishReportEvent; }
686
            set { finishReportEvent = value; }
687
        }
688

689
        /// <summary>
690
        /// Gets a value indicating that report execution was aborted.
691
        /// </summary>
692
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
693
        public bool Aborted
694
        {
695
            get
696
            {
697
                Config.DoEvent();
698
                return aborted;
699
            }
700
        }
701

702
        /// <summary>
703
        /// Gets or sets a value that determines whether to store the report in the application resources.
704
        /// Use this property in the MS Visual Studio IDE only.
705
        /// </summary>
706
        /// <remarks>
707
        /// By default this property is <b>true</b>. When set to <b>false</b>, you should store your report
708
        /// in a file.
709
        /// </remarks>
710
        [DefaultValue(true)]
711
        [SRCategory("Design")]
712
        public bool StoreInResources
713
        {
714
            get { return storeInResources; }
715
            set { storeInResources = value; }
716
        }
717

718
        /// <summary>
719
        /// Gets or sets the resource string that contains the report.
720
        /// </summary>
721
        /// <remarks>
722
        /// This property is used by the MS Visual Studio to store the report. Do not use it directly.
723
        /// </remarks>
724
        [Browsable(false)]
725
        [Localizable(true)]
726
        public string ReportResourceString
727
        {
728
            get
729
            {
730
                if (!StoreInResources)
731
                    return "";
732
                return SaveToString();
733
            }
734
            set
735
            {
736
                if (String.IsNullOrEmpty(value))
737
                {
738
                    Clear();
739
                    return;
740
                }
741
                LoadFromString(value);
742
            }
743
        }
744

745
        /// <summary>
746
        /// Gets a value indicating that this report contains dialog forms.
747
        /// </summary>
748
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
749
        public bool HasDialogs
750
        {
751
            get
752
            {
753
                foreach (PageBase page in Pages)
754
                {
755
                    if (page is DialogPage)
756
                        return true;
757
                }
758
                return false;
759
            }
760
        }
761

762
        /// <summary>
763
        /// Gets or sets a set of permissions that will be restricted for the script code.
764
        /// </summary>
765
        /// <remarks>
766
        /// Since the report script is compiled into .NET assembly, it allows you to do ANYTHING.
767
        /// For example, you may create a script that will read/write files from/to a disk. This property
768
        /// is used to restrict such operations.
769
        /// <example>This example shows how to restrict the file IO operations in a script:
770
        /// <code>
771
        /// using System.Security;
772
        /// using System.Security.Permissions;
773
        /// ...
774
        /// PermissionSet ps = new PermissionSet(PermissionState.None);
775
        /// ps.AddPermission(new FileIOPermission(PermissionState.Unrestricted));
776
        /// report1.ScriptRestrictions = ps;
777
        /// report1.Prepare();
778
        /// </code>
779
        /// </example>
780
        /// </remarks>
781
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
782
        public PermissionSet ScriptRestrictions
783
        {
784
            get { return scriptRestrictions; }
785
            set { scriptRestrictions = value; }
786
        }
787

788
        /// <summary>
789
        /// Gets a reference to the graphics cache for this report.
790
        /// </summary>
791
        /// <remarks>
792
        /// This property is used to support the FastReport.Net infrastructure. Do not use it directly.
793
        /// </remarks>
794
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
795
        public GraphicCache GraphicCache
796
        {
797
            get { return graphicCache; }
798
        }
799

800
        /// <summary>
801
        /// Gets a pages of the prepared report.
802
        /// </summary>
803
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
804
        public Preview.PreparedPages PreparedPages
805
        {
806
            get { return preparedPages; }
807
        }
808

809
        /// <summary>
810
        /// Gets a reference to the report engine.
811
        /// </summary>
812
        /// <remarks>
813
        /// This property can be used when report is running. In other cases it returns <b>null</b>.
814
        /// </remarks>
815
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
816
        public ReportEngine Engine
817
        {
818
            get { return engine; }
819
        }
820

821
        /// <summary>
822
        /// Gets or sets the initial page number for PageN/PageNofM system variables.
823
        /// </summary>
824
        [DefaultValue(1)]
825
        [SRCategory("Engine")]
826
        public int InitialPageNumber
827
        {
828
            get { return initialPageNumber; }
829
            set { initialPageNumber = value; }
830
        }
831

832
        /// <summary>
833
        /// This property is not relevant to this class.
834
        /// </summary>
835
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
836
        public new string Name
837
        {
838
            get { return base.Name; }
839
        }
840

841
        /// <summary>
842
        /// This property is not relevant to this class.
843
        /// </summary>
844
        [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
845
        public new Restrictions Restrictions
846
        {
847
            get { return base.Restrictions; }
848
            set { base.Restrictions = value; }
849
        }
850

851
        /// <summary>
852
        /// Gets the report operation that is currently performed.
853
        /// </summary>
854
        [Browsable(false)]
855
        public ReportOperation Operation
856
        {
857
            get { return operation; }
858
        }
859

860
        /// <summary>
861
        /// Gets or sets the Tag object of the report.
862
        /// </summary>
863
        [Browsable(false)]
864
        public object Tag
865
        {
866
            get { return tag; }
867
            set { tag = value; }
868
        }
869

870
        private string[] DefaultAssemblies
871
        {
872
            get
873
            {
874
                return new string[] {
875
                    "System.dll",
876

877
                    "System.Drawing.dll",
878

879
                    "System.Data.dll",
880

881
                    "System.Xml.dll",
882

883
                    "FastReport.Compat.dll",
884
#if !CROSSPLATFORM && !(WPF || AVALONIA)
885
                    "System.Windows.Forms.dll",
886
#endif
887

888
#if WPF
889
                    "FastReport.Forms.WPF.dll",
890
#endif
891

892
#if AVALONIA
893
                    "FastReport.Forms.Avalonia.dll",
894
#endif
895

896
#if CROSSPLATFORM || COREWIN
897
                    "System.Drawing.Primitives",
898
#endif
899

900
#if MSCHART
901
                    "FastReport.DataVisualization.dll"
902
#endif
903
                };
904
            }
905
        }
906

907
        internal CodeHelperBase CodeHelper
908
        {
909
            get { return codeHelper; }
910
        }
911

912
        public IGraphics MeasureGraphics
913
        {
914
            get
915
            {
916
                if (measureGraphics == null)
917
                {
918
#if CROSSPLATFORM || MONO
919
                    measureBitmap = new Bitmap(1, 1);
920
                    measureGraphics = new GdiGraphics(measureBitmap);
921
#else
922
                    measureGraphics = GdiGraphics.FromGraphics(Graphics.FromHwnd(IntPtr.Zero));
923
#endif
924
                }
925
                return measureGraphics;
926
            }
927
        }
928

929
        public string GetReportName
930
        {
931
            get
932
            {
933
                string result = ReportInfo.Name;
934
                if (String.IsNullOrEmpty(result))
935
                    result = Path.GetFileNameWithoutExtension(FileName);
936
                return result;
937
            }
938
        }
939

940
        /// <summary>
941
        /// Gets or sets the flag for refresh.
942
        /// </summary>
943
        public bool NeedRefresh
944
        {
945
            get { return needRefresh; }
946
            set { needRefresh = value; }
947
        }
948

949
        internal ObjectCollection AllNamedObjects
950
        {
951
            get
952
            {
953
                ObjectCollection allObjects = AllObjects;
954
                // data objects are not included into AllObjects list. Include named items separately.
955
                foreach (Base c in Dictionary.AllObjects)
956
                {
957
                    if (c is DataConnectionBase || c is DataSourceBase || c is Relation || c is CubeSourceBase)
958
                        allObjects.Add(c);
959
                }
960

961
                return allObjects;
962
            }
963
        }
964

965
        #endregion Properties
966

967
        #region Private Methods
968

969
        private bool ShouldSerializeReferencedAssemblies()
970
        {
971
            return Converter.ToString(ReferencedAssemblies) != Converter.ToString(DefaultAssemblies);
972
        }
973

974
        // convert absolute path to the base report to relative path (based on the main report path).
975
        private string GetRelativePathToBaseReport()
976
        {
977
            string path = "";
978
            if (!String.IsNullOrEmpty(FileName))
979
            {
980
                try
981
                {
982
                    path = Path.GetDirectoryName(FileName);
983
                }
984
                catch
985
                {
986
                }
987
            }
988

989
            if (!String.IsNullOrEmpty(path))
990
            {
991
                try
992
                {
993
                    return FileUtils.GetRelativePath(BaseReport, path);
994
                }
995
                catch
996
                {
997
                }
998
            }
999
            return BaseReport;
1000
        }
1001

1002
        private void SetBaseReport(string value)
1003
        {
1004
            baseReport = value;
1005
            if (baseReportObject != null)
1006
            {
1007
                baseReportObject.Dispose();
1008
                baseReportObject = null;
1009
            }
1010

1011
            // detach the base report
1012
            if (String.IsNullOrEmpty(value))
1013
            {
1014
                foreach (Base c in AllObjects)
1015
                {
1016
                    c.SetAncestor(false);
1017
                }
1018
                SetAncestor(false);
1019
                return;
1020
            }
1021

1022
            string saveFileName = fileName;
1023
            if (LoadBaseReport != null)
1024
            {
1025
                LoadBaseReport(this, new CustomLoadEventArgs(value, this));
1026
            }
1027
            else
1028
            {
1029
                // convert the relative path to absolute path (based on the main report path).
1030
                if (!Path.IsPathRooted(value))
1031
                {
1032
                    var fullPath = Path.GetFullPath(Path.GetDirectoryName(FileName));
1033
                    // since directory path separator for Win OS is  '\' and for Unix OS is '/'
1034
                    // we have to modify the incoming path string with actual for current OS path separator
1035
                    value = Path.Combine(fullPath, GetFixedSeparatedPath(value));
1036
                }
1037
                if (!File.Exists(value) && File.Exists(BaseReportAbsolutePath))
1038
                {
1039
                    value = BaseReportAbsolutePath;
1040
                }
1041
                Load(value);
1042
            }
1043

1044
            fileName = saveFileName;
1045
            baseReport = "";
1046
            Password = "";
1047
            baseReportObject = Activator.CreateInstance(GetType()) as Report;
1048
            baseReportObject.AssignAll(this, true);
1049

1050
            // set Ancestor & CanChangeParent flags
1051
            foreach (Base c in AllObjects)
1052
            {
1053
                c.SetAncestor(true);
1054
            }
1055
            SetAncestor(true);
1056
            baseReport = value;
1057
        }
1058

1059
        private static string GetFixedSeparatedPath(string baseReport)
1060
        {
1061
            return baseReport.Replace('/', Path.DirectorySeparatorChar).Replace('\\', Path.DirectorySeparatorChar);
1062
        }
1063

1064
        private void GetDiff(object sender, DiffEventArgs e)
1065
        {
1066
            if (baseReportObject != null)
1067
            {
1068
                if (e.Object is Report)
1069
                    e.DiffObject = baseReportObject;
1070
                else if (e.Object is Base)
1071
                    e.DiffObject = baseReportObject.FindObject((e.Object as Base).Name);
1072
            }
1073
        }
1074

1075
        private void ClearReportProperties()
1076
        {
1077
            ReportInfo.Clear();
1078
            Dictionary.Clear();
1079
            if (IsDesigning)
1080
            {
1081
                ScriptLanguage = Config.ReportSettings.DefaultLanguage;
1082
            }
1083
            else
1084
            {
1085
                ScriptLanguage = Language.CSharp;
1086
            }
1087
            // not property, only field!
1088
            scriptText = codeHelper.EmptyScript();
1089
            scriptChanged = false;
1090
            BaseReport = "";
1091
            BaseReportAbsolutePath = "";
1092
            DoublePass = false;
1093
            ConvertNulls = true;
1094
            Compressed = false;
1095
            TextQuality = TextQuality.Default;
1096
            SmoothGraphics = false;
1097
            Password = "";
1098
            InitialPageNumber = 1;
1099
            MaxPages = 0;
1100
            ClearDesign();
1101
            Styles.Clear();
1102
            Styles.Name = "";
1103
            referencedAssemblies = DefaultAssemblies;
1104
            StartReportEvent = "";
1105
            FinishReportEvent = "";
1106
#if REFLECTION_EMIT_COMPILER
1107
            _cachedParsedExpressions.Clear();
1108
#endif
1109
            needCompile = true;
1110
        }
1111

1112
        #endregion Private Methods
1113

1114
        #region Protected Methods
1115

1116
        /// <inheritdoc/>
1117
        protected override void Dispose(bool disposing)
1118
        {
1119
            if (disposing)
1120
            {
1121
                if (graphicCache != null)
1122
                    graphicCache.Dispose();
1123
                graphicCache = null;
1124
                if (measureGraphics != null)
1125
                    measureGraphics.Dispose();
1126
                measureGraphics = null;
1127
                if (measureBitmap != null)
1128
                    measureBitmap.Dispose();
1129
                measureBitmap = null;
1130
                DisposeDesign();
1131
                if (PreparedPages != null)
1132
                    PreparedPages.Dispose();
1133
            }
1134
            base.Dispose(disposing);
1135
        }
1136

1137
        /// <inheritdoc/>
1138
        protected override void DeserializeSubItems(FRReader reader)
1139
        {
1140
            if (String.Compare(reader.ItemName, "ScriptText", true) == 0)
1141
                ScriptText = reader.ReadPropertyValue();
1142
            else if (String.Compare(reader.ItemName, "Dictionary", true) == 0)
1143
                reader.Read(Dictionary);
1144
            else if (String.Compare(reader.ItemName, "Styles", true) == 0)
1145
                reader.Read(Styles);
1146
            else
1147
                base.DeserializeSubItems(reader);
1148
        }
1149

1150
        #endregion Protected Methods
1151

1152
        #region IParent
1153

1154
        /// <inheritdoc/>
1155
        public bool CanContain(Base child)
1156
        {
1157
            return child is PageBase || child is Dictionary;
1158
        }
1159

1160
        /// <inheritdoc/>
1161
        public void GetChildObjects(ObjectCollection list)
1162
        {
1163
            foreach (PageBase page in pages)
1164
            {
1165
                list.Add(page);
1166
            }
1167
        }
1168

1169
        /// <inheritdoc/>
1170
        public void AddChild(Base obj)
1171
        {
1172
            if (obj is PageBase)
1173
                pages.Add(obj as PageBase);
1174
            else if (obj is Dictionary)
1175
                Dictionary = obj as Dictionary;
1176
        }
1177

1178
        /// <inheritdoc/>
1179
        public void RemoveChild(Base obj)
1180
        {
1181
            if (obj is PageBase)
1182
                pages.Remove(obj as PageBase);
1183
            else if (obj is Dictionary && (obj as Dictionary) == dictionary)
1184
                Dictionary = null;
1185
        }
1186

1187
        /// <inheritdoc/>
1188
        public virtual int GetChildOrder(Base child)
1189
        {
1190
            if (child is PageBase)
1191
                return pages.IndexOf(child as PageBase);
1192
            return 0;
1193
        }
1194

1195
        /// <inheritdoc/>
1196
        public virtual void SetChildOrder(Base child, int order)
1197
        {
1198
            if (child is PageBase)
1199
            {
1200
                if (order > pages.Count)
1201
                    order = pages.Count;
1202
                int oldOrder = child.ZOrder;
1203
                if (oldOrder != -1 && order != -1 && oldOrder != order)
1204
                {
1205
                    if (oldOrder <= order)
1206
                        order--;
1207
                    pages.Remove(child as PageBase);
1208
                    pages.Insert(order, child as PageBase);
1209
                }
1210
            }
1211
        }
1212

1213
        /// <inheritdoc/>
1214
        public virtual void UpdateLayout(float dx, float dy)
1215
        {
1216
            // do nothing
1217
        }
1218

1219
        #endregion IParent
1220

1221
        #region ISupportInitialize Members
1222

1223
        /// <inheritdoc/>
1224
        public void BeginInit()
1225
        {
1226
            initializing = true;
1227
        }
1228

1229
        /// <inheritdoc/>
1230
        public void EndInit()
1231
        {
1232
            initializing = false;
1233
            Dictionary.RegisterData(initializeData, initializeDataName, false);
1234
        }
1235

1236
        #endregion ISupportInitialize Members
1237

1238
        #region Script related
1239

1240
        private void FillDataSourceCache()
1241
        {
1242
            cachedDataItems.Clear();
1243
            ObjectCollection dictionaryObjects = Dictionary.AllObjects;
1244
            foreach (Parameter c in Dictionary.SystemVariables)
1245
            {
1246
                dictionaryObjects.Add(c);
1247
            }
1248
            foreach (Base c in dictionaryObjects)
1249
            {
1250
                if (c is DataSourceBase)
1251
                {
1252
                    DataSourceBase data = c as DataSourceBase;
1253
                    CachedDataItem cachedItem = new CachedDataItem();
1254
                    cachedItem.dataSource = data;
1255
                    cachedDataItems[data.FullName] = cachedItem;
1256

1257
                    for (int i = 0; i < data.Columns.Count; i++)
1258
                    {
1259
                        cachedItem = new CachedDataItem();
1260
                        cachedItem.dataSource = data;
1261
                        cachedItem.column = data.Columns[i];
1262
                        cachedDataItems[data.FullName + "." + data.Columns[i].Alias] = cachedItem;
1263
                    }
1264
                }
1265
                else if (c is Parameter)
1266
                {
1267
                    cachedDataItems[(c as Parameter).FullName] = c;
1268
                }
1269
                else if (c is Total)
1270
                {
1271
                    cachedDataItems[(c as Total).Name] = c;
1272
                }
1273
            }
1274
        }
1275

1276
        internal void Compile()
1277
        {
1278
            FillDataSourceCache();
1279

1280
#if REFLECTION_EMIT_COMPILER
1281
            if (Config.CompilerSettings.ReflectionEmitCompiler)
1282
            {
1283
                SetIsCompileNeeded();
1284
                if (!IsCompileNeeded)
1285
                    return;
1286
            }
1287
#endif
1288

1289
            if (needCompile)
1290
            {
1291
                Debug.WriteLine("Compile...");
1292

1293
                using (AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText))
1294
                {
1295
                    assemblies.Clear();
1296
                    assemblies.Add(descriptor);
1297
                    descriptor.AddObjects();
1298
                    descriptor.AddExpressions();
1299
                    descriptor.AddFunctions();
1300
                    descriptor.Compile();
1301
                }
1302
            }
1303
            else
1304
            {
1305
                InternalInit();
1306
            }
1307
        }
1308

1309
#if ASYNC
1310
        internal async Task CompileAsync(CancellationToken token)
1311
        {
1312
            FillDataSourceCache();
1313

1314
#if REFLECTION_EMIT_COMPILER
1315
            if (Config.CompilerSettings.ReflectionEmitCompiler)
1316
            {
1317
                SetIsCompileNeeded();
1318
                if (!IsCompileNeeded)
1319
                    return;
1320
            }
1321
#endif
1322

1323
            if (needCompile)
1324
            {
1325
                AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText);
1326
                assemblies.Clear();
1327
                assemblies.Add(descriptor);
1328
                descriptor.AddObjects();
1329
                descriptor.AddExpressions();
1330
                descriptor.AddFunctions();
1331
                await descriptor.CompileAsync(token);
1332
            }
1333
            else
1334
            {
1335
                InternalInit();
1336
            }
1337
        }
1338
#endif
1339

1340
        /// <summary>
1341
        /// Initializes the report's fields.
1342
        /// </summary>
1343
        /// <remarks>
1344
        /// This method is for internal use only.
1345
        /// </remarks>
1346
        protected void InternalInit()
1347
        {
1348
            needCompile = false;
1349

1350
            AssemblyDescriptor descriptor = new AssemblyDescriptor(this, CodeHelper.EmptyScript());
1351
            assemblies.Clear();
1352
            assemblies.Add(descriptor);
1353
            descriptor.InitInstance(this);
1354
        }
1355

1356
        /// <summary>
1357
        /// Generates the file (.cs or .vb) that contains the report source code.
1358
        /// </summary>
1359
        /// <param name="fileName">Name of the file.</param>
1360
        /// <remarks>
1361
        /// Use this method to generate the report source code. This code can be attached to your project.
1362
        /// In this case, you will need to call the following code to run a report:
1363
        /// <code>
1364
        /// SimpleListReport report = new SimpleListReport();
1365
        /// report.RegisterData(your_dataset);
1366
        /// report.Show();
1367
        /// </code>
1368
        /// </remarks>
1369
        public void GenerateReportAssembly(string fileName)
1370
        {
1371
            // create the class name
1372
            string className = "";
1373
            const string punctuation = " ~`!@#$%^&*()-=+[]{},.<>/?;:'\"\\|";
1374
            foreach (char c in Path.GetFileNameWithoutExtension(fileName))
1375
            {
1376
                if (!punctuation.Contains(c.ToString()))
1377
                    className += c;
1378
            }
1379

1380
            AssemblyDescriptor descriptor = new AssemblyDescriptor(this, ScriptText);
1381
            descriptor.AddObjects();
1382
            descriptor.AddExpressions();
1383
            descriptor.AddFunctions();
1384

1385
            string reportClassText = descriptor.GenerateReportClass(className);
1386
            File.WriteAllText(fileName, reportClassText, Encoding.UTF8);
1387
        }
1388

1389
        /// <summary>
1390
        /// Calculates an expression and returns the result.
1391
        /// </summary>
1392
        /// <param name="expression">The expression to calculate.</param>
1393
        /// <returns>If report is running, returns the result of calculation.
1394
        /// Otherwise returns <b>null</b>.</returns>
1395
        /// <remarks>
1396
        /// <para>The expression may be any valid expression such as "1 + 2". The expression
1397
        /// is calculated in the report script's <b>ReportScript</b> class instance context,
1398
        /// so you may refer to any objects available in this context: private fields,
1399
        /// methods, report objects.</para>
1400
        /// </remarks>
1401
        public object Calc(string expression)
1402
        {
1403
            return Calc(expression, 0);
1404
        }
1405

1406
        /// <summary>
1407
        /// Calculates an expression and returns the result.
1408
        /// </summary>
1409
        /// <param name="expression">The expression to calculate.</param>
1410
        /// <param name="value">The value of currently printing object.</param>
1411
        /// <returns>If report is running, returns the result of calculation.
1412
        /// Otherwise returns <b>null</b>.</returns>
1413
        /// <remarks>
1414
        /// Do not call this method directly. Use the <b>Calc(string expression)</b> method instead.
1415
        /// </remarks>
1416
        public object Calc(string expression, Variant value)
1417
        {
1418
            if (!IsRunning)
1419
                return null;
1420
            if (String.IsNullOrEmpty(expression) || String.IsNullOrEmpty(expression.Trim()))
1421
                return null;
1422

1423
            string expr = expression;
1424
            if (expr.StartsWith("[") && expr.EndsWith("]"))
1425
                expr = expression.Substring(1, expression.Length - 2);
1426

1427
            // check cached items first
1428
            object cachedObject = cachedDataItems[expr];
1429

1430
            if (cachedObject is CachedDataItem)
1431
            {
1432
                CachedDataItem cachedItem = cachedObject as CachedDataItem;
1433
                DataSourceBase data = cachedItem.dataSource;
1434
                Column column = cachedItem.column;
1435

1436
                object val = ConvertToColumnDataType(column.Value, column.DataType, ConvertNulls);
1437

1438
                if (CustomCalc != null)
1439
                {
1440
                    CustomCalcEventArgs e = new CustomCalcEventArgs(expr, val, this);
1441
                    CustomCalc(this, e);
1442
                    val = e.CalculatedObject;
1443
                }
1444

1445
                return val;
1446
            }
1447
            else if (cachedObject is Parameter)
1448
            {
1449
                return (cachedObject as Parameter).Value;
1450
            }
1451
            else if (cachedObject is Total)
1452
            {
1453
                object val = (cachedObject as Total).Value;
1454
                if (ConvertNulls && (val == null || val is DBNull))
1455
                    val = 0;
1456

1457
                (cachedObject as Total).ExecuteTotal(val);
1458

1459
                return val;
1460
            }
1461

1462
            // calculate the expression
1463
            return CalcExpression(expression, value);
1464
        }
1465

1466
        private object ConvertToColumnDataType(object val, Type dataType, bool convertNulls)
1467
        {
1468
            if (val == null || val is DBNull)
1469
            {
1470
                if (convertNulls)
1471
                    val = Converter.ConvertNull(dataType);
1472
            }
1473
            else
1474
            {
1475
                if (val is IConvertible)
1476
                {
1477
                    Type t = Nullable.GetUnderlyingType(dataType);
1478
                    try
1479
                    {
1480
                        val = Convert.ChangeType(val, t != null ? t : dataType);
1481
                    }
1482
                    catch (InvalidCastException)
1483
                    {
1484
                        // do nothing
1485
                    }
1486
                    catch (FormatException)
1487
                    {
1488
                        // do nothing
1489
                    }
1490
                }
1491
            }
1492
            return val;
1493
        }
1494

1495
        /// <summary>
1496
        /// Returns an expression value.
1497
        /// </summary>
1498
        /// <param name="expression">The expression.</param>
1499
        /// <param name="value">The value of currently printing object.</param>
1500
        /// <returns>Returns the result of calculation.</returns>
1501
        /// <remarks>
1502
        /// This method is for internal use only, do not call it directly.
1503
        /// </remarks>
1504
        protected virtual object CalcExpression(string expression, Variant value)
1505
        {
1506
            if (expression.ToLower() == "true" || expression.ToLower() == "false")
1507
            {
1508
                expression = expression.ToLower();
1509
            }
1510

1511
            // try to calculate the expression
1512
            foreach (AssemblyDescriptor d in assemblies)
1513
            {
1514
                if (d.ContainsExpression(expression))
1515
                    return d.CalcExpression(expression, value);
1516
            }
1517

1518
#if REFLECTION_EMIT_COMPILER
1519
            if (Config.CompilerSettings.ReflectionEmitCompiler)
1520
                if (TryReflectionEmit(expression, value, out object returnValue))
1521
                    return returnValue;
1522
#endif
1523

1524
            // expression not found. Probably it was added after the start of the report.
1525
            // Compile new assembly containing this expression.
1526
            using (AssemblyDescriptor descriptor = new AssemblyDescriptor(this, CodeHelper.EmptyScript()))
1527
            {
1528
                assemblies.Add(descriptor);
1529
                descriptor.AddObjects();
1530
                descriptor.AddSingleExpression(expression);
1531
                descriptor.AddFunctions();
1532
                descriptor.Compile();
1533
                return descriptor.CalcExpression(expression, value);
1534
            }
1535
        }
1536

1537
        /// <summary>
1538
        /// Invokes the script method with given name.
1539
        /// </summary>
1540
        /// <param name="name">The name of the script method.</param>
1541
        /// <param name="parms">The method parameters.</param>
1542
        public object InvokeMethod(string name, object[] parms)
1543
        {
1544
            if (assemblies.Count > 0)
1545
                return assemblies[0].InvokeMethod(name, parms);
1546
            return null;
1547
        }
1548

1549
        private Column GetColumn(string complexName)
1550
        {
1551
            if (String.IsNullOrEmpty(complexName))
1552
                return null;
1553

1554
            CachedDataItem cachedItem = cachedDataItems[complexName] as CachedDataItem;
1555
            if (cachedItem != null)
1556
                return cachedItem.column;
1557

1558
            string[] names = complexName.Split('.');
1559
            cachedItem = cachedDataItems[names[0]] as CachedDataItem;
1560
            DataSourceBase data = cachedItem != null ? cachedItem.dataSource : GetDataSource(names[0]);
1561

1562
            return DataHelper.GetColumn(Dictionary, data, names, true);
1563
        }
1564

1565
        private object GetColumnValue(string complexName, bool convertNull)
1566
        {
1567
            Column column = GetColumn(complexName);
1568
            if (column == null)
1569
                return null;
1570

1571
            return ConvertToColumnDataType(column.Value, column.DataType, convertNull);
1572
        }
1573

1574
        private Variant GetTotalValue(string name, bool convertNull)
1575
        {
1576
            object value = Dictionary.Totals.GetValue(name);
1577
            if (convertNull && (value == null || value is DBNull))
1578
                value = 0;
1579

1580
            return new Variant(value);
1581
        }
1582

1583
        /// <summary>
1584
        /// Gets the data column's value. Automatically converts null value to 0, false or ""
1585
        /// depending on the column type.
1586
        /// </summary>
1587
        /// <param name="complexName">The name of the data column including the datasource name.</param>
1588
        /// <returns>If report is running, returns the column value. Otherwise returns <b>null</b>.</returns>
1589
        /// <remarks>
1590
        /// The return value of this method does not depend on the <see cref="ConvertNulls"/> property.
1591
        /// </remarks>
1592
        /// <example>
1593
        /// <code>
1594
        /// string employeeName = (string)report.GetColumnValue("Employees.FirstName");
1595
        /// </code>
1596
        /// </example>
1597
        public object GetColumnValue(string complexName)
1598
        {
1599
            return GetColumnValue(complexName, true);
1600
        }
1601

1602
        /// <summary>
1603
        /// Gets the data column's value. This method does not convert null values.
1604
        /// </summary>
1605
        /// <param name="complexName">The name of the data column including the datasource name.</param>
1606
        /// <returns>If report is running, returns the column value.
1607
        /// Otherwise returns <b>null</b>.</returns>
1608
        public object GetColumnValueNullable(string complexName)
1609
        {
1610
            return GetColumnValue(complexName, false);
1611
        }
1612

1613
        /// <summary>
1614
        /// Gets the report parameter with given name.
1615
        /// </summary>
1616
        /// <param name="complexName">The name of the parameter.</param>
1617
        /// <returns>The <see cref="Parameter"/> object if found, otherwise <b>null</b>.</returns>
1618
        /// <remarks>
1619
        /// To find nested parameter, use the "." separator: "MainParameter.NestedParameter"
1620
        /// </remarks>
1621
        public Parameter GetParameter(string complexName)
1622
        {
1623
            if (IsRunning)
1624
                return cachedDataItems[complexName] as Parameter;
1625
            return DataHelper.GetParameter(Dictionary, complexName);
1626
        }
1627

1628
        /// <summary>
1629
        /// Gets a value of the parameter with given name.
1630
        /// </summary>
1631
        /// <param name="complexName">The name of the parameter.</param>
1632
        /// <returns>The parameter's value if found, otherwise <b>null</b>.</returns>
1633
        /// <remarks>
1634
        /// To find nested parameter, use the "." separator: "MainParameter.NestedParameter"
1635
        /// </remarks>
1636
        public object GetParameterValue(string complexName)
1637
        {
1638
            Parameter par = GetParameter(complexName);
1639
            if (par != null)
1640
            {
1641
                // avoid InvalidCastException when casting object that is int to double
1642
                if (par.DataType.Name == "Double" && par.Value.GetType() == typeof(int))
1643
                {
1644
                    return (double)(int)par.Value;
1645
                }
1646
                return par.Value;
1647
            }
1648
            return null;
1649
        }
1650

1651
        /// <summary>
1652
        /// Sets the parameter's value.
1653
        /// </summary>
1654
        /// <param name="complexName">The name of the parameter.</param>
1655
        /// <param name="value">Value to set.</param>
1656
        /// <remarks>
1657
        /// Use this method to pass a value to the parameter that you've created in the "Data" window.
1658
        /// Such parameter may be used everythere in a report; for example, you can print its value
1659
        /// or use it in expressions.
1660
        /// <para/>You should call this method <b>after</b> the report was loaded and <b>before</b> you run it.
1661
        /// <para/>To access a nested parameter, use the "." separator: "MainParameter.NestedParameter"
1662
        /// <note type="caution">
1663
        /// This method will create the parameter if it does not exist.
1664
        /// </note>
1665
        /// </remarks>
1666
        /// <example>This example shows how to pass a value to the parameter with "MyParam" name:
1667
        /// <code>
1668
        /// // load the report
1669
        /// report1.Load("report.frx");
1670
        /// // setup the parameter
1671
        /// report1.SetParameterValue("MyParam", 10);
1672
        /// // show the report
1673
        /// report1.Show();
1674
        /// </code>
1675
        /// </example>
1676
        public void SetParameterValue(string complexName, object value)
1677
        {
1678
            Parameter par = GetParameter(complexName);
1679
            if (par == null)
1680
                par = DataHelper.CreateParameter(Dictionary, complexName);
1681
            if (par != null)
1682
            {
1683
                par.Value = value;
1684
                par.Expression = "";
1685
            }
1686

1687
            isParameterChanged = true;
1688
        }
1689

1690
        /// <summary>
1691
        /// Sets the parameter's expression.
1692
        /// </summary>
1693
        /// <param name="complexName">The name of the parameter.</param>
1694
        /// <param name="expression">Epression to set. It must be a valid FR expression.</param>
1695
        /// <remarks>
1696
        /// This method is used to create an expression for a parameter.
1697
        /// If the specified parameter does not exist, it will be created with the specified expression.
1698
        /// <br>
1699
        /// <b>Expression must be a valid FR expression to avoid exceptions.</b>
1700
        /// </br>
1701
        /// </remarks>
1702
        public void SetParameterExpression(string complexName, string expression)
1703
        {
1704
            Parameter par = GetParameter(complexName) ?? DataHelper.CreateParameter(Dictionary, complexName);
1705

1706
            if (par != null)
1707
            {
1708
                par.Expression = expression;
1709
            }
1710

1711
            isParameterChanged = true;
1712
        }
1713

1714
        /// <summary>
1715
        /// Gets a value of the system variable with specified name.
1716
        /// </summary>
1717
        /// <param name="complexName">Name of a variable.</param>
1718
        /// <returns>The variable's value if found, otherwise <b>null</b>.</returns>
1719
        public object GetVariableValue(string complexName)
1720
        {
1721
            return GetParameterValue(complexName);
1722
        }
1723

1724
        /// <summary>
1725
        /// Gets a value of the total with specified name.
1726
        /// </summary>
1727
        /// <param name="name">Name of total.</param>
1728
        /// <returns>The total's value if found, otherwise <b>0</b>.</returns>
1729
        /// <remarks>This method converts null values to 0 if the <see cref="ConvertNulls"/> property is set to true.
1730
        /// Use the <see cref="GetTotalValueNullable"/> method if you don't want the null conversion.
1731
        /// </remarks>
1732
        public Variant GetTotalValue(string name)
1733
        {
1734
            return GetTotalValue(name, ConvertNulls);
1735
        }
1736

1737
        /// <summary>
1738
        /// Gets a value of the total with specified name.
1739
        /// </summary>
1740
        /// <param name="name">Name of total.</param>
1741
        /// <returns>The total's value if found, otherwise <b>null</b>.</returns>
1742
        public Variant GetTotalValueNullable(string name)
1743
        {
1744
            return GetTotalValue(name, false);
1745
        }
1746

1747
        /// <summary>
1748
        /// Gets the datasource with specified name.
1749
        /// </summary>
1750
        /// <param name="alias">Alias name of a datasource.</param>
1751
        /// <returns>The datasource object if found, otherwise <b>null</b>.</returns>
1752
        public DataSourceBase GetDataSource(string alias)
1753
        {
1754
            return Dictionary.FindByAlias(alias) as DataSourceBase;
1755
        }
1756

1757
        #endregion Script related
1758

1759
        #region Public Methods
1760

1761
        /// <inheritdoc/>
1762
        public override void Assign(Base source)
1763
        {
1764
            BaseAssign(source);
1765
        }
1766

1767
        /// <summary>
1768
        /// Aborts the report execution.
1769
        /// </summary>
1770
        public void Abort()
1771
        {
1772
            SetAborted(true);
1773
        }
1774

1775
        /// <inheritdoc/>
1776
        public override Base FindObject(string name)
1777
        {
1778
            foreach (Base c in AllNamedObjects)
1779
            {
1780
                if (String.Compare(name, c.Name, true) == 0)
1781
                    return c;
1782
            }
1783
            return null;
1784
        }
1785

1786
        /// <inheritdoc/>
1787
        public override void Clear()
1788
        {
1789
            base.Clear();
1790
            ClearReportProperties();
1791
        }
1792

1793
        /// <summary>
1794
        /// Updates the report component's styles.
1795
        /// </summary>
1796
        /// <remarks>
1797
        /// Call this method if you change the <see cref="Styles"/> collection.
1798
        /// </remarks>
1799
        public void ApplyStyles()
1800
        {
1801
            foreach (Base c in AllObjects)
1802
            {
1803
                if (c is ReportComponentBase)
1804
                    (c as ReportComponentBase).Style = (c as ReportComponentBase).Style;
1805
            }
1806
        }
1807

1808
        /// <summary>
1809
        /// Sets prepared pages.
1810
        /// </summary>
1811
        /// <param name="pages"></param>
1812
        public void SetPreparedPages(Preview.PreparedPages pages)
1813
        {
1814
            preparedPages = pages;
1815
            if (pages != null)
1816
                pages.SetReport(this);
1817
        }
1818

1819
        internal void SetAborted(bool value)
1820
        {
1821
            aborted = value;
1822
        }
1823

1824
        internal void SetOperation(ReportOperation operation)
1825
        {
1826
            this.operation = operation;
1827
        }
1828

1829
        /// <summary>
1830
        /// This method fires the <b>StartReport</b> event and the script code connected
1831
        /// to the <b>StartReportEvent</b>.
1832
        /// </summary>
1833
        public void OnStartReport(EventArgs e)
1834
        {
1835
            SetRunning(true);
1836
            if (StartReport != null)
1837
                StartReport(this, e);
1838
            InvokeMethod(StartReportEvent, new object[] { this, e });
1839
        }
1840

1841
        /// <summary>
1842
        /// This method fires the <b>FinishReport</b> event and the script code connected
1843
        /// to the <b>FinishReportEvent</b>.
1844
        /// </summary>
1845
        public void OnFinishReport(EventArgs e)
1846
        {
1847
            SetRunning(false);
1848
            if (FinishReport != null)
1849
                FinishReport(this, e);
1850
            InvokeMethod(FinishReportEvent, new object[] { this, e });
1851
        }
1852

1853
        /// <summary>
1854
        /// Runs the Export event.
1855
        /// </summary>
1856
        /// <param name="e">ExportReportEventArgs object.</param>
1857
        public void OnExportParameters(ExportParametersEventArgs e)
1858
        {
1859
            if (ExportParameters != null)
1860
            {
1861
                ExportParameters(this, e);
1862
            }
1863
        }
1864

1865
        /// <summary>
1866
        /// Add the name of the assembly (in addition to the default) that will be used to compile the report script
1867
        /// </summary>
1868
        /// <param name="assembly_name">Assembly name</param>
1869
        /// <remarks>
1870
        /// For example: <code>report.AddReferencedAssembly("Newtonsoft.Json.dll")</code>
1871
        /// </remarks>
1872
        public void AddReferencedAssembly(string assembly_name)
1873
        {
1874
            string[] assemblies = ReferencedAssemblies;
1875
            Array.Resize(ref assemblies, assemblies.Length + 1);
1876
            assemblies[assemblies.Length - 1] = assembly_name;
1877
            ReferencedAssemblies = assemblies;
1878
        }
1879

1880
        /// <summary>
1881
        /// Add the names of the assembly (in addition to the default) that will be used to compile the report script
1882
        /// </summary>
1883
        /// <param name="assembly_names">Assembly's names</param>
1884
        public void AddReferencedAssembly(IList<string> assembly_names)
1885
        {
1886
            string[] assemblies = ReferencedAssemblies;
1887
            int oldLength = assemblies.Length;
1888
            Array.Resize(ref assemblies, oldLength + assembly_names.Count);
1889
            for (int i = 0; i < assembly_names.Count; i++)
1890
            {
1891
                assemblies[oldLength + i] = assembly_names[i];
1892
            }
1893
            ReferencedAssemblies = assemblies;
1894
        }
1895

1896
        /// <inheritdoc/>
1897
        public override void Serialize(FRWriter writer)
1898
        {
1899
            Report c = writer.DiffObject as Report;
1900
            writer.ItemName = IsAncestor ? "inherited" : ClassName;
1901
            if (BaseReport != c.BaseReport)
1902
            {
1903
                // when save to the report file, convert absolute path to the base report to relative path
1904
                // (based on the main report path). Do not convert when saving to the clipboard.
1905
                string value = writer.SerializeTo != SerializeTo.Undo ? GetRelativePathToBaseReport() : BaseReport;
1906
                writer.WriteStr("BaseReport", value);
1907
                // Fix bug with moving child report to another folder without parent report.
1908
                if (writer.SerializeTo == SerializeTo.Report)
1909
                    writer.WriteStr("BaseReportAbsolutePath", BaseReport);
1910
            }
1911
            // always serialize ScriptLanguage because its default value depends on Config.ReportSettings.DefaultLanguage
1912
            writer.WriteValue("ScriptLanguage", ScriptLanguage);
1913
            if (ScriptText != c.ScriptText)
1914
                writer.WritePropertyValue("ScriptText", ScriptText);
1915
            if (!writer.AreEqual(ReferencedAssemblies, c.ReferencedAssemblies))
1916
                writer.WriteValue("ReferencedAssemblies", ReferencedAssemblies);
1917
            if (ConvertNulls != c.ConvertNulls)
1918
                writer.WriteBool("ConvertNulls", ConvertNulls);
1919
            if (DoublePass != c.DoublePass)
1920
                writer.WriteBool("DoublePass", DoublePass);
1921
            if (Compressed != c.Compressed)
1922
                writer.WriteBool("Compressed", Compressed);
1923
            if (UseFileCache != c.UseFileCache)
1924
                writer.WriteBool("UseFileCache", UseFileCache);
1925
            if (TextQuality != c.TextQuality)
1926
                writer.WriteValue("TextQuality", TextQuality);
1927
            if (SmoothGraphics != c.SmoothGraphics)
1928
                writer.WriteBool("SmoothGraphics", SmoothGraphics);
1929
            if (Password != c.Password)
1930
                writer.WriteStr("Password", Password);
1931
            if (InitialPageNumber != c.InitialPageNumber)
1932
                writer.WriteInt("InitialPageNumber", InitialPageNumber);
1933
            if (MaxPages != c.MaxPages)
1934
                writer.WriteInt("MaxPages", MaxPages);
1935
            if (StartReportEvent != c.StartReportEvent)
1936
                writer.WriteStr("StartReportEvent", StartReportEvent);
1937
            if (FinishReportEvent != c.FinishReportEvent)
1938
                writer.WriteStr("FinishReportEvent", FinishReportEvent);
1939
            ReportInfo.Serialize(writer, c.ReportInfo);
1940
            SerializeDesign(writer, c);
1941
            if (Styles.Count > 0)
1942
                writer.Write(Styles);
1943
            writer.Write(Dictionary);
1944
            if (writer.SaveChildren)
1945
            {
1946
                foreach (Base child in ChildObjects)
1947
                {
1948
                    writer.Write(child);
1949
                }
1950
            }
1951
        }
1952

1953
        /// <inheritdoc/>
1954
        public override void Deserialize(FRReader reader)
1955
        {
1956
            if (reader.HasProperty("BaseReportAbsolutePath"))
1957
            {
1958
                BaseReportAbsolutePath = reader.ReadStr("BaseReportAbsolutePath");
1959
            }
1960

1961
            base.Deserialize(reader);
1962

1963
            // call OnAfterLoad method of each report object
1964
            foreach (Base c in AllObjects)
1965
            {
1966
                c.OnAfterLoad();
1967
            }
1968
        }
1969

1970
        /// <summary>
1971
        /// Saves the report to a stream.
1972
        /// </summary>
1973
        /// <param name="stream">The stream to save to.</param>
1974
        public void Save(Stream stream)
1975
        {
1976
            using (FRWriter writer = new FRWriter())
1977
            {
1978
                if (IsAncestor)
1979
                    writer.GetDiff += new DiffEventHandler(GetDiff);
1980
                writer.Write(this);
1981

1982
                List<Stream> disposeList = new List<Stream>();
1983

1984
                if (Compressed)
1985
                {
1986
                    stream = Compressor.Compress(stream);
1987
                    disposeList.Add(stream);
1988
                }
1989
                if (!String.IsNullOrEmpty(Password))
1990
                {
1991
                    stream = Crypter.Encrypt(stream, Password);
1992
                    disposeList.Insert(0, stream);
1993
                }
1994
                writer.Save(stream);
1995

1996
                foreach (Stream s in disposeList)
1997
                {
1998
                    s.Dispose();
1999
                }
2000
            }
2001
        }
2002

2003
        /// <summary>
2004
        /// Saves the report to a file.
2005
        /// </summary>
2006
        /// <param name="fileName">The name of the file to save to.</param>
2007
        public void Save(string fileName)
2008
        {
2009
            FileName = fileName;
2010
            using (FileStream f = new FileStream(fileName, FileMode.Create))
2011
            {
2012
                Save(f);
2013
            }
2014
        }
2015

2016
        /// <summary>
2017
        /// Saves the report to a stream with randomized values in data sources.
2018
        /// </summary>
2019
        /// <param name="stream">The stream to save to.</param>
2020
        public void SaveWithRandomData(Stream stream)
2021
        {
2022
            FRRandom random = new FRRandom();
2023
            random.RandomizeDataSources(Dictionary.DataSources);
2024
            Save(stream);
2025
        }
2026

2027
        /// <summary>
2028
        /// Saves the report to a file with randomized values in data sources.
2029
        /// </summary>
2030
        /// <param name="fileName">The name of the file to save to.</param>
2031
        public void SaveWithRandomData(string fileName)
2032
        {
2033
            FRRandom random = new FRRandom();
2034
            random.RandomizeDataSources(Dictionary.DataSources);
2035
            Save(fileName);
2036
        }
2037

2038
        /// <summary>
2039
        /// Loads report from a stream.
2040
        /// </summary>
2041
        /// <param name="stream">The stream to load from.</param>
2042
        /// <remarks>
2043
        /// The stream must be seekable.
2044
        /// When you load a password-protected report, you should specify a password in the <see cref="Password"/> property,
2045
        /// otherwise you will get the <see cref="DecryptException"/>. In this case you should ask for a password and try again:
2046
        /// <code>
2047
        /// try
2048
        /// {
2049
        ///   report.Load(stream);
2050
        /// }
2051
        /// catch (DecryptException)
2052
        /// {
2053
        ///   report.Password = report.ShowPasswordForm(); // or use your own form to do this
2054
        ///   report.Load(stream);
2055
        /// }
2056
        /// </code>
2057
        /// </remarks>
2058
        public void Load(Stream stream)
2059
        {
2060
            string password = Password;
2061
            Clear();
2062

2063
            var saveStream = stream;
2064
            var saveStreamPos = stream.Position;
2065

2066
            using (FRReader reader = new FRReader(this))
2067
            {
2068
                List<Stream> disposeList = new List<Stream>();
2069
                if (Compressor.IsStreamCompressed(stream))
2070
                {
2071
                    stream = Compressor.Decompress(stream, true);
2072
                    disposeList.Add(stream);
2073
                }
2074
                bool crypted = Crypter.IsStreamEncrypted(stream);
2075
                if (crypted)
2076
                {
2077
                    stream = Crypter.Decrypt(stream, password);
2078
                    disposeList.Add(stream);
2079
                }
2080

2081
                try
2082
                {
2083
                    reader.Load(stream);
2084
                }
2085
                catch (Exception e)
2086
                {
2087
                    if (crypted)
2088
                    {
2089
                        saveStream.Position = saveStreamPos;
2090
                        throw new DecryptException();
2091
                    }
2092
                    throw e;
2093
                }
2094
                finally
2095
                {
2096
                    foreach (Stream s in disposeList)
2097
                    {
2098
                        try
2099
                        {
2100
                            s.Dispose();
2101
                        }
2102
                        catch
2103
                        {
2104
                        }
2105
                    }
2106
                }
2107

2108
                reader.Read(this);
2109
            }
2110
        }
2111

2112
        /// <summary>
2113
        /// Loads the report from a file.
2114
        /// </summary>
2115
        /// <param name="fileName">The name of the file to load from.</param>
2116
        /// <remarks>
2117
        /// When you try to load the password-protected report, you will be asked
2118
        /// for a password. You also may specify the password in the <see cref="Password"/>
2119
        /// property before loading the report. In this case the report will load silently.
2120
        /// </remarks>
2121
        public void Load(string fileName)
2122
        {
2123
            this.fileName = "";
2124
            using (FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read))
2125
            {
2126
                this.fileName = fileName;
2127
                Load(f);
2128
            }
2129
        }
2130

2131
        /// <summary>
2132
        /// Loads the report from a string.
2133
        /// </summary>
2134
        /// <param name="s">The string that contains a stream in UTF8 or Base64 encoding.</param>
2135
        public void LoadFromString(string s)
2136
        {
2137
            if (String.IsNullOrEmpty(s))
2138
                return;
2139

2140
            byte[] buffer;
2141
            int startIndex = s.IndexOf("<?xml version=\"1.0\" encoding=\"utf-8\"?>");
2142
            if (startIndex != -1)
2143
            {
2144
                buffer = Encoding.UTF8.GetBytes(s.Substring(startIndex));
2145
            }
2146
            else
2147
            {
2148
                buffer = Convert.FromBase64String(s);
2149
            }
2150

2151
            using (MemoryStream stream = new MemoryStream(buffer))
2152
            {
2153
                Load(stream);
2154
            }
2155
        }
2156

2157
        /// <summary>
2158
        /// Saves the report to a string.
2159
        /// </summary>
2160
        /// <returns>The string that contains a stream.</returns>
2161
        public string SaveToString()
2162
        {
2163
            using (MemoryStream stream = new MemoryStream())
2164
            {
2165
                Save(stream);
2166

2167
                if (Compressed || !String.IsNullOrEmpty(Password))
2168
                {
2169
                    return Convert.ToBase64String(stream.ToArray());
2170
                }
2171
                else
2172
                {
2173
                    return Encoding.UTF8.GetString(stream.ToArray());
2174
                }
2175
            }
2176
        }
2177

2178
        /// <summary>
2179
        /// Saves the report to a string using the Base64 encoding.
2180
        /// </summary>
2181
        /// <returns>The string that contains a stream.</returns>
2182
        public string SaveToStringBase64()
2183
        {
2184
            using (MemoryStream stream = new MemoryStream())
2185
            {
2186
                Save(stream);
2187
                return Convert.ToBase64String(stream.ToArray());
2188
            }
2189
        }
2190

2191
        /// <summary>
2192
        /// Creates the report instance and loads the report from a stream.
2193
        /// </summary>
2194
        /// <param name="stream">The stream to load from.</param>
2195
        /// <returns>The new report instance.</returns>
2196
        public static Report FromStream(Stream stream)
2197
        {
2198
            Report result = new Report();
2199
            result.Load(stream);
2200
            return result;
2201
        }
2202

2203
        /// <summary>
2204
        /// Creates the report instance and loads the report from a file.
2205
        /// </summary>
2206
        /// <param name="fileName">The name of the file to load from.</param>
2207
        /// <returns>The new report instance.</returns>
2208
        public static Report FromFile(string fileName)
2209
        {
2210
            Report result = new Report();
2211
            result.Load(fileName);
2212
            return result;
2213
        }
2214

2215
        /// <summary>
2216
        /// Creates the report instance and loads the report from a string.
2217
        /// </summary>
2218
        /// <param name="utf8String">The string that contains a stream in UTF8 encoding.</param>
2219
        /// <returns>The new report instance.</returns>
2220
        public static Report FromString(string utf8String)
2221
        {
2222
            Report result = new Report();
2223
            result.LoadFromString(utf8String);
2224
            return result;
2225
        }
2226

2227
        /// <summary>
2228
        /// Registers the application dataset with all its tables and relations to use it in the report.
2229
        /// </summary>
2230
        /// <param name="data">The application data.</param>
2231
        /// <remarks>
2232
        /// If you register more than one dataset, use the <see cref="RegisterData(DataSet, string)"/> method.
2233
        /// </remarks>
2234
        /// <example>
2235
        /// <code>
2236
        /// report1.Load("report.frx");
2237
        /// report1.RegisterData(dataSet1);
2238
        /// </code>
2239
        /// </example>
2240
        public void RegisterData(DataSet data)
2241
        {
2242
            Dictionary.RegisterDataSet(data, "Data", false);
2243
        }
2244

2245
        /// <summary>
2246
        /// Registers the application dataset with all its tables and relations to use it in the report and enables all its tables.
2247
        /// </summary>
2248
        /// <param name="data">The application data.</param>
2249
        /// <param name="enableAllTables">The boolean value indicating whether all tables should be enabled.</param>
2250
        /// <remarks>
2251
        /// If you register more than one dataset, use the <see cref="RegisterData(DataSet, string)"/> method.
2252
        /// </remarks>
2253
        /// <example>
2254
        /// <code>
2255
        /// report1.Load("report.frx");
2256
        /// report1.RegisterData(dataSet1, true);
2257
        /// </code>
2258
        /// </example>
2259
        public void RegisterData(DataSet data, bool enableAllTables)
2260
        {
2261
            Dictionary.RegisterDataSet(data, "Data", false);
2262
            foreach (DataTable table in data.Tables)
2263
            {
2264
                DataSourceBase ds = Report.GetDataSource(table.TableName);
2265
                if (ds != null)
2266
                    ds.Enabled = true;
2267
            }
2268
        }
2269

2270
        /// <summary>
2271
        /// Registers the application dataset with specified name.
2272
        /// </summary>
2273
        /// <param name="data">The application data.</param>
2274
        /// <param name="name">The name of the data.</param>
2275
        /// <remarks>
2276
        /// Use this method if you register more than one dataset. You may specify any value
2277
        /// for the <b>name</b> parameter: it is not displayed anywhere in the designer and used only
2278
        /// to load/save a report. The name must be persistent and unique for each registered dataset.
2279
        /// </remarks>
2280
        /// <example>
2281
        /// <code>
2282
        /// report1.Load("report.frx");
2283
        /// report1.RegisterData(dataSet1, "NorthWind");
2284
        /// </code>
2285
        /// </example>
2286
        public void RegisterData(DataSet data, string name)
2287
        {
2288
            if (initializing)
2289
            {
2290
                initializeData = data;
2291
                initializeDataName = name;
2292
            }
2293
            else
2294
                Dictionary.RegisterDataSet(data, name, false);
2295
        }
2296

2297
        /// <summary>
2298
        /// Registers the application dataset with specified name and enables all its tables.
2299
        /// </summary>
2300
        /// <param name="data">The application data.</param>
2301
        /// <param name="name">The name of the data.</param>
2302
        /// <param name="enableAllTables">The boolean value indicating whether all tables should be enabled.</param>
2303
        /// <remarks>
2304
        /// Use this method if you register more than one dataset. You may specify any value
2305
        /// for the <b>name</b> parameter: it is not displayed anywhere in the designer and used only
2306
        /// to load/save a report. The name must be persistent and unique for each registered dataset.
2307
        /// </remarks>
2308
        /// <example>
2309
        /// <code>
2310
        /// report1.Load("report.frx");
2311
        /// report1.RegisterData(dataSet1, "NorthWind", true);
2312
        /// </code>
2313
        /// </example>
2314
        public void RegisterData(DataSet data, string name, bool enableAllTables)
2315
        {
2316
            if (initializing)
2317
            {
2318
                initializeData = data;
2319
                initializeDataName = name;
2320
            }
2321
            else
2322
            {
2323
                Dictionary.RegisterDataSet(data, name, false);
2324
                foreach (DataTable table in data.Tables)
2325
                {
2326
                    DataSourceBase ds = Report.GetDataSource(table.TableName);
2327
                    if (ds != null)
2328
                        ds.Enabled = true;
2329
                }
2330
            }
2331
        }
2332

2333
        /// <summary>
2334
        /// Registers the application data table to use it in the report.
2335
        /// </summary>
2336
        /// <param name="data">The application data.</param>
2337
        /// <param name="name">The name of the data.</param>
2338
        /// <example>
2339
        /// <code>
2340
        /// report1.Load("report.frx");
2341
        /// report1.RegisterData(dataSet1.Tables["Orders"], "Orders");
2342
        /// </code>
2343
        /// </example>
2344
        public void RegisterData(DataTable data, string name)
2345
        {
2346
            Dictionary.RegisterDataTable(data, name, false);
2347
        }
2348

2349
        /// <summary>
2350
        /// Registers the application data view to use it in the report.
2351
        /// </summary>
2352
        /// <param name="data">The application data.</param>
2353
        /// <param name="name">The name of the data.</param>
2354
        /// <example>
2355
        /// <code>
2356
        /// report1.Load("report.frx");
2357
        /// report1.RegisterData(myDataView, "OrdersView");
2358
        /// </code>
2359
        /// </example>
2360
        public void RegisterData(DataView data, string name)
2361
        {
2362
            Dictionary.RegisterDataView(data, name, false);
2363
        }
2364

2365
        /// <summary>
2366
        /// Registers the application data relation to use it in the report.
2367
        /// </summary>
2368
        /// <param name="data">The application data.</param>
2369
        /// <param name="name">The name of the data.</param>
2370
        /// <remarks>
2371
        /// You may specify any value for the <b>name</b> parameter: it is not displayed anywhere
2372
        /// in the designer and used only to load/save a report. The name must be persistent
2373
        /// and unique for each registered relation.
2374
        /// </remarks>
2375
        /// <example>
2376
        /// <code>
2377
        /// report1.Load("report.frx");
2378
        /// report1.RegisterData(myDataRelation, "myRelation");
2379
        /// </code>
2380
        /// </example>
2381
        public void RegisterData(DataRelation data, string name)
2382
        {
2383
            Dictionary.RegisterDataRelation(data, name, false);
2384
        }
2385

2386
        /// <summary>
2387
        /// <b>Obsolete</b>. Registers the application business object to use it in the report.
2388
        /// </summary>
2389
        /// <param name="data">Application data.</param>
2390
        /// <param name="name">Name of the data.</param>
2391
        /// <param name="flags">Not used.</param>
2392
        /// <param name="maxNestingLevel">Maximum nesting level of business objects.</param>
2393
        /// <remarks>
2394
        /// This method is obsolete. Use the <see cref="RegisterData(IEnumerable, string)"/> method instead.
2395
        /// </remarks>
2396
        public void RegisterData(IEnumerable data, string name, BOConverterFlags flags, int maxNestingLevel)
2397
        {
2398
            RegisterData(data, name, maxNestingLevel);
2399
        }
2400

2401
        /// <summary>
2402
        /// Registers the application business object to use it in the report.
2403
        /// </summary>
2404
        /// <param name="data">Application data.</param>
2405
        /// <param name="name">Name of the data.</param>
2406
        /// <example>
2407
        /// <code>
2408
        /// report1.Load("report.frx");
2409
        /// report1.RegisterData(myBusinessObject, "Customers");
2410
        /// </code>
2411
        /// </example>
2412
        public void RegisterData(IEnumerable data, string name)
2413
        {
2414
            if (initializing)
2415
            {
2416
                initializeData = data;
2417
                initializeDataName = name;
2418
            }
2419
            else
2420
                Dictionary.RegisterBusinessObject(data, name, 1, false);
2421
        }
2422

2423
        /// <summary>
2424
        /// Registers the application business object to use it in the report.
2425
        /// </summary>
2426
        /// <param name="data">Application data.</param>
2427
        /// <param name="name">Name of the data.</param>
2428
        /// <param name="maxNestingLevel">Maximum nesting level of business objects.</param>
2429
        /// <remarks>
2430
        /// This method creates initial datasource with specified nesting level. It is useful if
2431
        /// you create a report in code. In most cases, you don't need to specify the nesting level
2432
        /// because it may be selected in the designer's "Choose Report Data" dialog.
2433
        /// </remarks>
2434
        public void RegisterData(IEnumerable data, string name, int maxNestingLevel)
2435
        {
2436
            Dictionary.RegisterBusinessObject(data, name, maxNestingLevel, false);
2437
        }
2438

2439
        /// <summary>
2440
        /// Registers the application cube link to use it in the report.
2441
        /// </summary>
2442
        /// <param name="data">The application data.</param>
2443
        /// <param name="name">The name of the data.</param>
2444
        /// <example>
2445
        /// <code>
2446
        /// report1.Load("report.frx");
2447
        /// report1.RegisterData(myCubeLink, "Orders");
2448
        /// </code>
2449
        /// </example>
2450
        public void RegisterData(IBaseCubeLink data, string name)
2451
        {
2452
            Dictionary.RegisterCubeLink(data, name, false);
2453
        }
2454

2455
        /// <summary>
2456
        /// Prepares the report.
2457
        /// </summary>
2458
        /// <returns><b>true</b> if report was prepared succesfully.</returns>
2459
        public bool Prepare()
2460
        {
2461
            return Prepare(false);
2462
        }
2463

2464
#if ASYNC
2465
        /// <summary>
2466
        /// Prepares the report asynchronously.
2467
        /// </summary>
2468
        /// <param name="token">Cancellation token</param>
2469
        /// <returns><b>true</b> if report was prepared succesfully.</returns>
2470
        [EditorBrowsable(EditorBrowsableState.Never)] // TODO
2471
        public Task<bool> PrepareAsync(CancellationToken token = default)
2472
        {
2473
            return PrepareAsync(false, token);
2474
        }
2475

2476
        private async Task<bool> PrepareAsync(bool append, CancellationToken token = default)
2477
        {
2478
            SetRunning(true);
2479
            try
2480
            {
2481
                if (PreparedPages == null || !append)
2482
                {
2483
                    ClearPreparedPages();
2484

2485
                    SetPreparedPages(new Preview.PreparedPages(this));
2486
                }
2487
                engine = new ReportEngine(this);
2488

2489
                if (!Config.WebMode)
2490
                    StartPerformanceCounter();
2491

2492
                try
2493
                {
2494
                    await CompileAsync(token).ConfigureAwait(false);
2495
                    isParameterChanged = false;
2496
                    return Engine.Run(true, append, true);
2497
                }
2498
                finally
2499
                {
2500
                    if (!Config.WebMode)
2501
                        StopPerformanceCounter();
2502
                }
2503
            }
2504
            finally
2505
            {
2506
                SetRunning(false);
2507
            }
2508
        }
2509

2510
#endif
2511

2512
        /// <summary>
2513
        /// Prepares the report.
2514
        /// </summary>
2515
        /// <param name="append">Specifies whether the new report should be added to a
2516
        /// report that was prepared before.</param>
2517
        /// <returns><b>true</b> if report was prepared succesfully.</returns>
2518
        /// <remarks>
2519
        /// Use this method to merge prepared reports.
2520
        /// </remarks>
2521
        /// <example>This example shows how to merge two reports and preview the result:
2522
        /// <code>
2523
        /// Report report = new Report();
2524
        /// report.Load("report1.frx");
2525
        /// report.Prepare();
2526
        /// report.Load("report2.frx");
2527
        /// report.Prepare(true);
2528
        /// report.ShowPrepared();
2529
        /// </code>
2530
        /// </example>
2531
        public bool Prepare(bool append)
2532
        {
2533
            SetRunning(true);
2534
            try
2535
            {
2536
                if (PreparedPages == null || !append)
2537
                {
2538
                    ClearPreparedPages();
2539

2540
                    SetPreparedPages(new Preview.PreparedPages(this));
2541
                }
2542
                engine = new ReportEngine(this);
2543

2544
                if (!Config.WebMode)
2545
                    StartPerformanceCounter();
2546

2547
                try
2548
                {
2549
                    Compile();
2550
                    isParameterChanged = false;
2551
                    return Engine.Run(true, append, true);
2552
                }
2553
                finally
2554
                {
2555
                    if (!Config.WebMode)
2556
                        StopPerformanceCounter();
2557
                }
2558
            }
2559
            finally
2560
            {
2561
                SetRunning(false);
2562
            }
2563
        }
2564

2565
        /// <summary>
2566
        /// Prepares the report with pages limit.
2567
        /// </summary>
2568
        /// <param name="pagesLimit">Pages limit. The number of pages equal or less will be prepared.</param>
2569
        /// <returns><b>true</b> if report was prepared succesfully.</returns>
2570
        public bool Prepare(int pagesLimit)
2571
        {
2572
            SetRunning(true);
2573
            try
2574
            {
2575
                ClearPreparedPages();
2576
                SetPreparedPages(new Preview.PreparedPages(this));
2577
                engine = new ReportEngine(this);
2578

2579
                if (!Config.WebMode)
2580
                    StartPerformanceCounter();
2581

2582
                try
2583
                {
2584
                    Compile();
2585
                    return Engine.Run(true, false, true, pagesLimit);
2586
                }
2587
                finally
2588
                {
2589
                    if (!Config.WebMode)
2590
                        StopPerformanceCounter();
2591
                }
2592
            }
2593
            finally
2594
            {
2595
                SetRunning(false);
2596
            }
2597
        }
2598

2599
        /// <summary>
2600
        /// For internal use only.
2601
        /// </summary>
2602
        [EditorBrowsable(EditorBrowsableState.Never)]
2603
        public void PreparePhase1()
2604
        {
2605
            bool webDialog = false;
2606
            SetRunning(true);
2607
            if (preparedPages != null)
2608
            {
2609
                // if prepared pages are set before => it's call method again => it's web dialog
2610
                webDialog = true;
2611
                preparedPages.Clear();
2612
            }
2613
            SetPreparedPages(new Preview.PreparedPages(this));
2614
            engine = new ReportEngine(this);
2615
            Compile();
2616
            Engine.RunPhase1(true, webDialog);
2617
        }
2618

2619
        /// <summary>
2620
        /// For internal use only.
2621
        /// </summary>
2622
        [EditorBrowsable(EditorBrowsableState.Never)]
2623
        public void PreparePhase2(int? pagesLimit = null)
2624
        {
2625
            Engine.RunPhase2(pagesLimit);
2626
            SetRunning(false);
2627
        }
2628

2629
        /// <summary>
2630
        /// Refresh the current report.
2631
        /// </summary>
2632
        /// <remarks>
2633
        /// Call this method in the Click or MouseUp event handler of a report object to refresh
2634
        /// the currently previewed report. Report will be generated again, but without dialog forms.
2635
        /// </remarks>
2636
        public void Refresh()
2637
        {
2638
            needRefresh = true;
2639
        }
2640

2641
        /// <summary>
2642
        ///  Refresh prepared report after interactive actions.
2643
        /// </summary>
2644
        public void InteractiveRefresh()
2645
        {
2646
            PreparedPages.ClearPageCache();
2647
            InternalRefresh();
2648
        }
2649

2650
        /// <summary>
2651
        /// Serialize report object from string
2652
        /// </summary>
2653
        /// <returns>Serialized report object from string</returns>
2654
        [EditorBrowsable(EditorBrowsableState.Never)]
2655
        public ReportComponentBase Xml(string xml)
2656
        {
2657
            XmlDocument doc = new XmlDocument();
2658
            using (TextReader reader = new StringReader(xml))
2659
            {
2660
                doc.WriteHeader = false;
2661
                doc.ReadHeader = true;
2662
                doc.Load(reader);
2663

2664
            }
2665
            using (FRReader reader = new FRReader(this, doc.Root))
2666
            {
2667

2668
                reader.DeserializeFrom = SerializeTo.Clipboard;
2669
                return reader.Read() as ReportComponentBase;
2670
            }
2671
        }
2672

2673

2674
        internal void InternalRefresh()
2675
        {
2676
            SetRunning(true);
2677
            try
2678
            {
2679
                Engine.Run(false, false, false);
2680
            }
2681
            finally
2682
            {
2683
                SetRunning(false);
2684
            }
2685
        }
2686

2687

2688
        internal TextRenderingHint GetTextQuality()
2689
        {
2690
            switch (this.TextQuality)
2691
            {
2692
                case TextQuality.Regular:
2693
                    return TextRenderingHint.AntiAliasGridFit;
2694

2695
                case TextQuality.ClearType:
2696
                    return TextRenderingHint.ClearTypeGridFit;
2697

2698
                case TextQuality.AntiAlias:
2699
                    return TextRenderingHint.AntiAlias;
2700

2701
                case TextQuality.SingleBPP:
2702
                    return TextRenderingHint.SingleBitPerPixel;
2703

2704
                case TextQuality.SingleBPPGridFit:
2705
                    return TextRenderingHint.SingleBitPerPixelGridFit;
2706
            }
2707

2708
            return TextRenderingHint.SystemDefault;
2709
        }
2710

2711

2712
        /// <summary>
2713
        /// Prepare page
2714
        /// </summary>
2715
        /// <param name="page"></param>
2716
        public void PreparePage(ReportPage page)
2717
        {
2718
            SetRunning(true);
2719
            try
2720
            {
2721
                Engine.Run(false, false, false, page);
2722
            }
2723
            finally
2724
            {
2725
                SetRunning(false);
2726
            }
2727
        }
2728

2729
        /// <summary>
2730
        /// Prepare page
2731
        /// </summary>
2732
        /// <param name="page"></param>
2733
        /// <param name="isDetailPage"> Flag indicating whether the page is a detail page. </param>
2734
        public void PreparePage(ReportPage page, bool isDetailPage)
2735
        {
2736
            bool pageVisible = page.Visible;
2737
            if (isDetailPage)
2738
                page.Visible = true;
2739
            PreparePage(page);
2740
            page.Visible = pageVisible;
2741
        }
2742

2743
        /// <summary>
2744
        /// Exports a report. Report should be prepared using the <see cref="Prepare()"/> method.
2745
        /// </summary>
2746
        /// <param name="export">The export filter.</param>
2747
        /// <param name="stream">Stream to save export result to.</param>
2748
        public void Export(ExportBase export, Stream stream)
2749
        {
2750
            export.Export(this, stream);
2751
        }
2752

2753
        /// <summary>
2754
        /// Exports a report. Report should be prepared using the <see cref="Prepare()"/> method.
2755
        /// </summary>
2756
        /// <param name="export">The export filter.</param>
2757
        /// <param name="fileName">File name to save export result to.</param>
2758
        public void Export(ExportBase export, string fileName)
2759
        {
2760
            export.Export(this, fileName);
2761
        }
2762

2763
        /// <summary>
2764
        /// Saves the prepared report. Report should be prepared using the <see cref="Prepare()"/> method.
2765
        /// </summary>
2766
        /// <param name="fileName">File name to save to.</param>
2767
        public void SavePrepared(string fileName)
2768
        {
2769
            if (PreparedPages != null)
2770
                PreparedPages.Save(fileName);
2771
        }
2772

2773
        /// <summary>
2774
        /// Saves the prepared report. Report should be prepared using the <see cref="Prepare()"/> method.
2775
        /// </summary>
2776
        /// <param name="stream">Stream to save to.</param>
2777
        public void SavePrepared(Stream stream)
2778
        {
2779
            if (PreparedPages != null)
2780
                PreparedPages.Save(stream);
2781
        }
2782

2783
        /// <summary>
2784
        /// Loads the prepared report from a .fpx file.
2785
        /// </summary>
2786
        /// <param name="fileName">File name to load form.</param>
2787
        public void LoadPrepared(string fileName)
2788
        {
2789
            isLoadPrepared = true;
2790
            if (PreparedPages == null)
2791
                SetPreparedPages(new FastReport.Preview.PreparedPages(this));
2792
            PreparedPages.Load(fileName);
2793
        }
2794

2795
        /// <summary>
2796
        /// Loads the prepared report from a .fpx file.
2797
        /// </summary>
2798
        /// <param name="stream">Stream to load from.</param>
2799
        public void LoadPrepared(Stream stream)
2800
        {
2801
            isLoadPrepared = true;
2802
            if (PreparedPages == null)
2803
                SetPreparedPages(new FastReport.Preview.PreparedPages(this));
2804
            PreparedPages.Load(stream);
2805
        }
2806

2807
        #endregion Public Methods
2808

2809
        /// <summary>
2810
        /// Initializes a new instance of the <see cref="Report"/> class with default settings.
2811
        /// </summary>
2812
        public Report()
2813
        {
2814
            pages = new PageCollection(this);
2815
            reportInfo = new ReportInfo();
2816
            InitDesign();
2817
            styles = new StyleCollection();
2818
            Dictionary = new Dictionary();
2819
            graphicCache = new GraphicCache();
2820
            assemblies = new AssemblyCollection();
2821
            cachedDataItems = new Hashtable(StringComparer.InvariantCultureIgnoreCase); // needed for case insensitivity
2822
            storeInResources = true;
2823
            fileName = "";
2824
            autoFillDataSet = true;
2825
            tag = null;
2826
            ClearReportProperties();
2827
            SetFlags(Flags.CanMove | Flags.CanResize | Flags.CanDelete | Flags.CanEdit | Flags.CanChangeOrder |
2828
              Flags.CanChangeParent | Flags.CanCopy, false);
2829
            //FInlineImageCache = new InlineImageCache();
2830
        }
2831

2832
        static Report()
2833
        {
2834
            Config.Init();
2835
        }
2836

2837
        /// <summary>
2838
        /// Ensure that static constructor is called.
2839
        /// </summary>
2840
        public static void EnsureInit()
2841
        {
2842
            // do nothing, just ensure that static constructor is called.
2843
        }
2844

2845
        /// <summary>
2846
        /// Create name for all unnamed elements with prefix and start with number
2847
        /// </summary>
2848
        /// <param name="prefix">Prefix for name</param>
2849
        /// <param name="number">Number from which to start</param>
2850
        public void PostNameProcess(string prefix, int number)
2851
        {
2852
            int i = number;
2853

2854
            foreach (Base obj in AllObjects)
2855
            {
2856
                if (String.IsNullOrEmpty(obj.Name))
2857
                {
2858
                    obj.SetName(prefix + i.ToString());
2859
                    i++;
2860
                }
2861
            }
2862
        }
2863

2864
        private class CachedDataItem
2865
        {
2866
            public DataSourceBase dataSource;
2867
            public Column column;
2868
        }
2869
    }
2870
}

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.