From 0765292897094e04bac937cad3029780fa9364da Mon Sep 17 00:00:00 2001 From: David Berneda Date: Fri, 1 Jul 2016 18:56:33 +0200 Subject: [PATCH] Beta 14 --- .../Expressions/BI.FMX.Expression.Tree.pas | 8 + .../firemonkey/Expressions/Main_Unit.fmx | 52 +- .../firemonkey/Expressions/Main_Unit.pas | 45 +- .../Expressions/TeeBI_Expressions_Test.dproj | 36 +- .../vcl/Dashboards/Editor/BIVisual_Editor.dpr | 17 + .../Dashboards/Editor/BIVisual_Editor.dproj | 540 ++++++++++++++++++ .../vcl/Dashboards/Editor/BIVisual_Editor.res | Bin 0 -> 58468 bytes .../vcl/Dashboards/Editor/Unit_Main.dfm | 100 ++++ .../vcl/Dashboards/Editor/Unit_Main.pas | 81 +++ .../vcl/Dashboards/Templates/customers.json | 45 ++ .../delphi/vcl/Grid/Detail/BIGrid_Detail.dpr | 14 + .../vcl/Grid/Detail/BIGrid_Detail.dproj | 528 +++++++++++++++++ .../delphi/vcl/Grid/Detail/BIGrid_Detail.res | Bin 0 -> 59212 bytes .../vcl/Grid/Detail/Unit_Grid_Detail.dfm | 64 +++ .../vcl/Grid/Detail/Unit_Grid_Detail.pas | 60 ++ demos/delphi/vcl/Import/Import_ByCode.dfm | 31 +- demos/delphi/vcl/Import/Import_ByCode.pas | 6 + demos/delphi/vcl/MapReduce/BI_MapReduce.dpr | 3 +- demos/delphi/vcl/MapReduce/BI_MapReduce.dproj | 14 +- demos/delphi/vcl/MapReduce/Unit_Main.dfm | 4 + demos/delphi/vcl/MapReduce/Unit_Main.pas | 2 + .../vcl/Master-Detail/Master_Detail_Unit.dfm | 1 + .../vcl/Search/Unit_DataSearch_Demo.pas | 20 +- demos/lazarus/BIGrid/project1.lps | 283 ++++++--- demos/lazarus/BIGrid/unit1.lfm | 30 +- demos/lazarus/BIGrid/unit1.pas | 15 +- server/Apache/VCL/BI.Web.ApacheContext.pas | 146 +++++ server/Apache/VCL/BIWeb.ModuleUnit.Apache.dfm | 14 + server/Apache/VCL/BIWeb.ModuleUnit.Apache.pas | 94 +++ server/Apache/VCL/BIWeb_Apache.dpr | 48 ++ server/Apache/VCL/BIWeb_Apache.dproj | 474 +++++++++++++++ server/Apache/VCL/BIWeb_Apache.res | Bin 0 -> 57492 bytes server/BI.Web.AllData.pas | 16 +- server/BI.Web.Common.pas | 13 +- server/fmx/BI_FMX_Web.res | Bin 18264 -> 19004 bytes server/vcl/BI_VCL_Web.dproj | 61 +- server/vcl/BI_VCL_Web.res | Bin 18264 -> 19004 bytes .../Algorithms/BI.Plugins.Python.Engine.pas | 5 +- src/delphi/BI.Arrays.pas | 22 +- src/delphi/BI.Compare.pas | 8 +- src/delphi/BI.Dashboard.HTML.pas | 6 +- src/delphi/BI.Dashboard.Layouts.pas | 86 +++ src/delphi/BI.Dashboard.Loader.pas | 91 +++ src/delphi/BI.Dashboard.pas | 443 ++++++++------ src/delphi/BI.Data.CSV.pas | 6 +- src/delphi/BI.Data.DB.BDE.pas | 3 +- src/delphi/BI.Data.DB.FireDAC.AllDrivers.pas | 18 +- src/delphi/BI.Data.DB.FireDAC.pas | 3 +- src/delphi/BI.Data.DB.SqlExpr.pas | 7 +- src/delphi/BI.Data.DB.pas | 15 +- src/delphi/BI.Data.Dataset.pas | 1 + src/delphi/BI.Data.Expressions.pas | 18 +- src/delphi/BI.Data.Html.pas | 4 +- src/delphi/BI.Data.RTTI.pas | 27 +- src/delphi/BI.Data.SQL.pas | 18 +- src/delphi/BI.Data.Search.pas | 19 +- src/delphi/BI.Data.SingleRecord.pas | 37 ++ src/delphi/BI.Data.SqlDB.pas | 3 +- src/delphi/BI.Data.Workflow.pas | 7 +- src/delphi/BI.Data.pas | 10 +- src/delphi/BI.Expression.Filter.pas | 118 ++-- src/delphi/BI.Expression.pas | 36 +- src/delphi/BI.FPC.pas | 28 +- src/delphi/BI.Languages.English.pas | 17 + src/delphi/BI.MapReduce.pas | 34 +- src/delphi/BI.Persist.pas | 50 +- src/delphi/BI.Schedule.pas | 2 +- src/delphi/BI.Store.Component.pas | 4 +- src/delphi/BI.Streams.pas | 14 +- src/delphi/BI.Summary.pas | 4 +- src/delphi/BI.Tree.pas | 2 +- src/delphi/BI.UI.Colors.pas | 28 +- src/delphi/BI.UI.pas | 1 + src/delphi/BI.Web.FPC.pas | 8 +- src/delphi/BI.Web.Indy.pas | 1 - src/delphi/BI.Web.pas | 2 + src/delphi/FMX/BI.FMX.Component.pas | 2 + src/delphi/FMX/BI.FMX.Dashboard.Chart.pas | 2 +- src/delphi/FMX/BI.FMX.Dashboard.pas | 131 +++-- src/delphi/FMX/BI.FMX.DataManager.fmx | 8 +- src/delphi/FMX/BI.FMX.Grid.pas | 4 +- src/delphi/FMX/BI.FMX.Tree.TeeTree.pas | 85 +++ src/delphi/FMX/BI.FMX.Tree.TreeView.pas | 37 +- src/delphi/FMX/BI.FMX.Tree.pas | 37 +- src/delphi/Packages/DclFmxTeeBI.dpk | 1 + src/delphi/Packages/FMXTeeBI.dpk | 1 + src/delphi/Packages/TeeBI.dpk | 3 + src/delphi/Packages/TeeBIAbout.dfm | Bin 1021 -> 1021 bytes src/delphi/Packages/TeeBIAbout.pas | 7 - src/delphi/Packages/TeeBIFMXAbout.pas | 46 ++ src/delphi/Packages/VCLTeeBI.dpk | 5 + src/delphi/VCL/BI.VCL.Component.pas | 2 + src/delphi/VCL/BI.VCL.Dashboard.Chart.pas | 2 +- src/delphi/VCL/BI.VCL.Dashboard.pas | 131 +++-- src/delphi/VCL/BI.VCL.DataSelect.dfm | 10 +- src/delphi/VCL/BI.VCL.DataSelect.pas | 5 +- src/delphi/VCL/BI.VCL.DataViewer.dfm | 69 ++- src/delphi/VCL/BI.VCL.DataViewer.pas | 7 + src/delphi/VCL/BI.VCL.DataWorkflow.pas | 7 + .../VCL/BI.VCL.Designer.Template.Layouts.dfm | 258 +++++++++ .../VCL/BI.VCL.Designer.Template.Layouts.pas | 105 ++++ src/delphi/VCL/BI.VCL.Editor.BIGrid.dfm | 11 +- src/delphi/VCL/BI.VCL.Editor.BIGrid.pas | 2 + src/delphi/VCL/BI.VCL.Editor.Chart.dfm | 12 + src/delphi/VCL/BI.VCL.Editor.Data.dfm | 65 ++- src/delphi/VCL/BI.VCL.Editor.Data.pas | 8 + .../VCL/BI.VCL.Editor.DataComponent.pas | 10 +- src/delphi/VCL/BI.VCL.Editor.DataSelect.dfm | 13 - src/delphi/VCL/BI.VCL.Editor.DataSet.dfm | 19 - .../VCL/BI.VCL.Editor.DateTimeRange.dfm | 371 ++++++------ .../VCL/BI.VCL.Editor.DateTimeRange.pas | 48 +- .../VCL/BI.VCL.Editor.DynamicFilter.dfm | 71 ++- .../VCL/BI.VCL.Editor.DynamicFilter.pas | 9 +- src/delphi/VCL/BI.VCL.Editor.Expression.pas | 6 + src/delphi/VCL/BI.VCL.Editor.ListItems.dfm | 1 - src/delphi/VCL/BI.VCL.Editor.ListItems.pas | 1 - .../VCL/BI.VCL.Editor.NumericFromTo.dfm | 2 +- .../VCL/BI.VCL.Editor.NumericFromTo.pas | 2 + src/delphi/VCL/BI.VCL.Editor.Query.dfm | 36 ++ src/delphi/VCL/BI.VCL.Editor.Query.pas | 1 + .../VCL/BI.VCL.Editor.Template.Data.dfm | 86 +++ .../VCL/BI.VCL.Editor.Template.Data.pas | 44 ++ .../VCL/BI.VCL.Editor.Template.Layouts.dfm | 123 ++++ .../VCL/BI.VCL.Editor.Template.Layouts.pas | 50 ++ .../VCL/BI.VCL.Editor.Template.Panels.dfm | 83 +++ .../VCL/BI.VCL.Editor.Template.Panels.pas | 45 ++ src/delphi/VCL/BI.VCL.Editor.Template.dfm | 499 ++++++++++++++++ src/delphi/VCL/BI.VCL.Editor.Template.pas | 148 +++++ src/delphi/VCL/BI.VCL.Grid.DBGrid.pas | 13 +- src/delphi/VCL/BI.VCL.Grid.pas | 6 +- src/delphi/VCL/BI.VCL.GridForm.dfm | 15 +- src/delphi/VCL/BI.VCL.GridForm.pas | 7 +- src/delphi/VCL/BI.VCL.Tree.TeeTree.pas | 85 +++ src/delphi/VCL/BI.VCL.Tree.TreeView.pas | 19 +- .../VCL/BI.VCL.Tree.VirtualTreeView.pas | 78 +++ src/delphi/VCL/BI.VCL.Tree.pas | 37 +- 136 files changed, 6127 insertions(+), 935 deletions(-) create mode 100644 demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dpr create mode 100644 demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dproj create mode 100644 demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.res create mode 100644 demos/delphi/vcl/Dashboards/Editor/Unit_Main.dfm create mode 100644 demos/delphi/vcl/Dashboards/Editor/Unit_Main.pas create mode 100644 demos/delphi/vcl/Dashboards/Templates/customers.json create mode 100644 demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dpr create mode 100644 demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dproj create mode 100644 demos/delphi/vcl/Grid/Detail/BIGrid_Detail.res create mode 100644 demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.dfm create mode 100644 demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.pas create mode 100644 server/Apache/VCL/BI.Web.ApacheContext.pas create mode 100644 server/Apache/VCL/BIWeb.ModuleUnit.Apache.dfm create mode 100644 server/Apache/VCL/BIWeb.ModuleUnit.Apache.pas create mode 100644 server/Apache/VCL/BIWeb_Apache.dpr create mode 100644 server/Apache/VCL/BIWeb_Apache.dproj create mode 100644 server/Apache/VCL/BIWeb_Apache.res create mode 100644 src/delphi/BI.Dashboard.Layouts.pas create mode 100644 src/delphi/BI.Dashboard.Loader.pas create mode 100644 src/delphi/BI.Data.SingleRecord.pas create mode 100644 src/delphi/FMX/BI.FMX.Tree.TeeTree.pas create mode 100644 src/delphi/Packages/TeeBIFMXAbout.pas create mode 100644 src/delphi/VCL/BI.VCL.Designer.Template.Layouts.dfm create mode 100644 src/delphi/VCL/BI.VCL.Designer.Template.Layouts.pas create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.Data.dfm create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.Data.pas create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.Layouts.dfm create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.Layouts.pas create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.Panels.dfm create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.Panels.pas create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.dfm create mode 100644 src/delphi/VCL/BI.VCL.Editor.Template.pas create mode 100644 src/delphi/VCL/BI.VCL.Tree.TeeTree.pas create mode 100644 src/delphi/VCL/BI.VCL.Tree.VirtualTreeView.pas diff --git a/demos/delphi/firemonkey/Expressions/BI.FMX.Expression.Tree.pas b/demos/delphi/firemonkey/Expressions/BI.FMX.Expression.Tree.pas index 75be950..a647662 100644 --- a/demos/delphi/firemonkey/Expressions/BI.FMX.Expression.Tree.pas +++ b/demos/delphi/firemonkey/Expressions/BI.FMX.Expression.Tree.pas @@ -79,6 +79,14 @@ procedure FillTree(const ATree:TTreeView; const AExpression:TExpression); tmp:=NewNode('not'); AddNodes(tmp,TUnaryExpression(AExpression).Expression); end + else + if AExpression is TIfExpression then + begin + tmp:=NewNode(TIfExpression(AExpression).Condition.ToString); + + AddNodes(tmp,TIfExpression(AExpression).ThenExpression); + AddNodes(tmp,TIfExpression(AExpression).ElseExpression); + end else NewNode(AExpression.ToString) end; diff --git a/demos/delphi/firemonkey/Expressions/Main_Unit.fmx b/demos/delphi/firemonkey/Expressions/Main_Unit.fmx index 5ec75cc..dfe88eb 100644 --- a/demos/delphi/firemonkey/Expressions/Main_Unit.fmx +++ b/demos/delphi/firemonkey/Expressions/Main_Unit.fmx @@ -16,14 +16,14 @@ object FormMain: TFormMain Size.Width = 393.000000000000000000 Size.Height = 600.000000000000000000 Size.PlatformDefault = False - TabIndex = 0 + TabIndex = 1 TabOrder = 11 TabPosition = PlatformDefault object TabTest: TTabItem CustomIcon = < item end> - IsSelected = True + IsSelected = False Size.Width = 41.000000000000000000 Size.Height = 26.000000000000000000 Size.PlatformDefault = False @@ -196,28 +196,28 @@ object FormMain: TFormMain CustomIcon = < item end> - IsSelected = False - Size.Width = 69.000000000000000000 + IsSelected = True + Size.Width = 51.000000000000000000 Size.Height = 26.000000000000000000 Size.PlatformDefault = False StyleLookup = '' TabOrder = 0 - Text = 'Examples' + Text = 'Other' ExplicitSize.cx = 69.000000000000000000 ExplicitSize.cy = 26.000000000000000000 object BExampleFormula: TButton Position.X = 24.000000000000000000 - Position.Y = 39.000000000000000000 + Position.Y = 22.000000000000000000 Size.Width = 233.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False - TabOrder = 19 + TabOrder = 21 Text = 'x:= (3*2) + Sqr(4) - 7' OnClick = BExampleFormulaClick end object Button2: TButton Position.X = 24.000000000000000000 - Position.Y = 72.000000000000000000 + Position.Y = 56.000000000000000000 Size.Width = 233.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False @@ -227,17 +227,17 @@ object FormMain: TFormMain end object Button3: TButton Position.X = 24.000000000000000000 - Position.Y = 140.000000000000000000 + Position.Y = 125.000000000000000000 Size.Width = 233.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False - TabOrder = 6 + TabOrder = 8 Text = 'Animals Size>7 and Name<>'#39'Ocelot'#39 OnClick = Button3Click end object Button4: TButton Position.X = 24.000000000000000000 - Position.Y = 105.000000000000000000 + Position.Y = 90.000000000000000000 Size.Width = 233.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False @@ -249,7 +249,7 @@ object FormMain: TFormMain Touch.InteractiveGestures = [LongTap, DoubleTap] TabOrder = 1 Position.X = 24.000000000000000000 - Position.Y = 184.000000000000000000 + Position.Y = 269.000000000000000000 Size.Width = 233.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False @@ -258,7 +258,7 @@ object FormMain: TFormMain end object BEvaluate: TButton Position.X = 24.000000000000000000 - Position.Y = 216.000000000000000000 + Position.Y = 301.000000000000000000 Size.Width = 80.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False @@ -269,22 +269,42 @@ object FormMain: TFormMain object Button5: TButton Enabled = False Position.X = 176.000000000000000000 - Position.Y = 216.000000000000000000 + Position.Y = 301.000000000000000000 Size.Width = 80.000000000000000000 Size.Height = 22.000000000000000000 Size.PlatformDefault = False - TabOrder = 8 + TabOrder = 10 Text = '&Edit...' OnClick = Button5Click end object LabelResult: TLabel Position.X = 24.000000000000000000 - Position.Y = 248.000000000000000000 + Position.Y = 333.000000000000000000 Size.Width = 233.000000000000000000 Size.Height = 17.000000000000000000 Size.PlatformDefault = False Text = '?' end + object Button1: TButton + Position.X = 24.000000000000000000 + Position.Y = 159.000000000000000000 + Size.Width = 233.000000000000000000 + Size.Height = 22.000000000000000000 + Size.PlatformDefault = False + TabOrder = 7 + Text = 'RTTI Expression' + OnClick = Button1Click + end + object Button6: TButton + Position.X = 24.000000000000000000 + Position.Y = 194.000000000000000000 + Size.Width = 233.000000000000000000 + Size.Height = 22.000000000000000000 + Size.PlatformDefault = False + TabOrder = 6 + Text = 'If Expression then A else B' + OnClick = Button6Click + end end end object Layout2: TLayout diff --git a/demos/delphi/firemonkey/Expressions/Main_Unit.pas b/demos/delphi/firemonkey/Expressions/Main_Unit.pas index b23bc54..53b250d 100644 --- a/demos/delphi/firemonkey/Expressions/Main_Unit.pas +++ b/demos/delphi/firemonkey/Expressions/Main_Unit.pas @@ -66,6 +66,8 @@ TFormMain = class(TForm) Layout2: TLayout; TreeView1: TTreeView; Splitter1: TSplitter; + Button1: TButton; + Button6: TButton; procedure BEvaluateClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); @@ -78,6 +80,8 @@ TFormMain = class(TForm) procedure BTestAllClick(Sender: TObject); procedure BExampleFormulaClick(Sender: TObject); procedure Button8Click(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Button6Click(Sender: TObject); private { Private declarations } @@ -102,7 +106,7 @@ TFormMain = class(TForm) implementation uses - BI.Arrays, BI.Data.Expressions, + BI.Arrays, BI.Data.Expressions, BI.Data.RTTI, BI.FMX.Expression.Tree, BI.Expression.Benchmark; {$R *.fmx} @@ -112,6 +116,18 @@ procedure TFormMain.BEvaluateClick(Sender: TObject); LabelResult.Text:=Expression.Value; end; +procedure TFormMain.Button1Click(Sender: TObject); +begin + Expression.Free; + + Expression:=TObjectExpression.From(Button1,'Text'); + + Present; + + BEvaluate.Enabled:=True; + BEvaluateClick(Self); +end; + procedure TFormMain.Button2Click(Sender: TObject); begin Expression.Free; @@ -203,6 +219,27 @@ procedure TFormMain.Button5Click(Sender: TObject); // TExpressionEditor.Edit(Self,Expression); end; +procedure TFormMain.Button6Click(Sender: TObject); +begin + Expression.Free; + + // " if Edit1.Text = 'S' then 'Spain' else 'Brazil' " + Expression:=TIfExpression.Create( + TLogicalExpression.Create( + TObjectExpression.From(Edit1,'Text'), + TLogicalOperand.Equal, + TTextExpression.Create('S') + ), + TTextExpression.Create('Spain'), + TTextExpression.Create('Brazil') + ); + + ShowTree; + + BEvaluate.Enabled:=True; + BEvaluateClick(Self); +end; + // Parse and evaluate S string to verify the expression procedure TFormMain.TestExpression(const S:String); var Value, @@ -303,8 +340,10 @@ procedure TFormMain.ParseExpression(const AExpression:String); begin // Parse error, unknown identifier - LabelResult.Text:='Unknown: '+S; - result:=nil; + result:=TObjectExpression.Parse(Self,S); + + if result=nil then + LabelResult.Text:='Unknown: '+S; end, function(const APos:Integer; const Text:String):Boolean begin diff --git a/demos/delphi/firemonkey/Expressions/TeeBI_Expressions_Test.dproj b/demos/delphi/firemonkey/Expressions/TeeBI_Expressions_Test.dproj index 2c5ca17..2cd6c72 100644 --- a/demos/delphi/firemonkey/Expressions/TeeBI_Expressions_Test.dproj +++ b/demos/delphi/firemonkey/Expressions/TeeBI_Expressions_Test.dproj @@ -5,7 +5,7 @@ FMX TeeBI_Expressions_Test.dpr True - Release + Debug Win32 31 Application @@ -308,27 +308,12 @@ true - - - 0 - .dll;.bpl - + 1 - .dylib - - - Contents\MacOS - 1 - .dylib 1 - .dylib - - - 1 - .dylib @@ -692,12 +677,27 @@ 1 - + + + 0 + .dll;.bpl + 1 + .dylib + + + Contents\MacOS + 1 + .dylib 1 + .dylib + + + 1 + .dylib diff --git a/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dpr b/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dpr new file mode 100644 index 0000000..585f0ca --- /dev/null +++ b/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dpr @@ -0,0 +1,17 @@ +program BIVisual_Editor; + +uses + Vcl.Forms, + Unit_Main in 'Unit_Main.pas' {Form34}; + +{$R *.res} + +begin + {$IFOPT D+} + ReportMemoryLeaksOnShutdown:=True; + {$ENDIF} + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TForm34, Form34); + Application.Run; +end. diff --git a/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dproj b/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dproj new file mode 100644 index 0000000..fc79a35 --- /dev/null +++ b/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.dproj @@ -0,0 +1,540 @@ + + + {552FFCB1-DFC2-4C5B-8359-726A6EBDDD63} + 18.1 + VCL + BIVisual_Editor.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + BIVisual_Editor + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + $(BDS)\bin\default_app.manifest + 1033 + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;TMSFMXPackPkgDEDXE9;FlexCel_Pdf;vclactnband;FMX_FlexCel_Core;vclFireDAC;emsclientfiredac;TeeDB923;DataSnapFireDAC;svnui;tethering;TeeLanguage923;FireDACADSDriver;FMXTee923;TMSFMXPackPkgDXE9;TeeMaker123;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;FlexCel_Report;inetdb;FireDACIBDriver;fmx;fmxdae;VCL_FlexCel_Components;vclib;TeeGL923;Tee923;FireDACDBXDriver;dbexpress;IndyCore;FMXChartProTeeBI;vclx;dsnap;DataSnapCommon;emsclient;TeeWorld923;FireDACCommon;TeeBI;FMXTeeBI;RESTBackendComponents;DataSnapConnectors;FMXTree23;VCLRESTComponents;FMXTeePro923;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FixInsight_10;VCLChartProTeeBI;FireDACCommonDriver;hclcore_xe10;DataSnapClient;LockBoxDR;inet;bindcompdbx;IndyIPCommon;TeeImport923;vcl;DBXSybaseASEDriver;IndyIPServer;TeeImage923;TeeUI923;IndySystem;FMXTeeDB923;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;FlexCel_XlsAdapter;TeeTree2D23Tee9;FMXTeeImport923;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;htmlcompfm_xe10;DBXOdbcDriver;FireDACTDataDriver;VCLTeeBI;soaprtl;DbxCommonDriver;FlexCel_Core;ibxpress;htmlcomp_xe10;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;TeePro923;DBXSybaseASADriver;FmxTeeUI923;CustomIPTransport;vcldsnap;FMXTeeLanguage923;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;FMX_FlexCel_Components;vclribbon;dbxcds;VclSmp;VCL_FlexCel_Core;adortl;FireDACODBCDriver;FlexCel_Render;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;mySQLDAC23;fmxase;$(DCC_UsePackage) + true + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + + + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;FlexCel_Pdf;vclactnband;FMX_FlexCel_Core;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;FlexCel_Report;inetdb;FireDACIBDriver;fmx;fmxdae;VCL_FlexCel_Components;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;FireDACCommon;TeeBI;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;VCLChartProTeeBI;FireDACCommonDriver;hclcore_xe10;DataSnapClient;LockBoxDR;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;FlexCel_XlsAdapter;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;VCLTeeBI;soaprtl;DbxCommonDriver;FlexCel_Core;ibxpress;htmlcomp_xe10;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;FMX_FlexCel_Components;vclribbon;dbxcds;VclSmp;VCL_FlexCel_Core;adortl;FireDACODBCDriver;FlexCel_Render;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;mySQLDAC23;fmxase;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + 1033 + true + c:\root\teebee\sources;c:\root\teebee\sources\vcl;$(DCC_UnitSearchPath) + true + true + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + true + + + + MainSource + + +
Form34
+ dfm +
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + BIVisual_Editor.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + BIVisual_Editor.exe + true + + + + + 1 + + + 1 + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + library\lib\mips + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + library\lib\x86 + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ../ + 1 + + + ../ + 1 + + + + + res\drawable-hdpi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + Contents + 1 + + + + + ../ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.res b/demos/delphi/vcl/Dashboards/Editor/BIVisual_Editor.res new file mode 100644 index 0000000000000000000000000000000000000000..20ba553086005b9f4e8e7a6bee3fe14bfc0a7654 GIT binary patch literal 58468 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 L{#(}nNdNx>?6uf> literal 0 HcmV?d00001 diff --git a/demos/delphi/vcl/Dashboards/Editor/Unit_Main.dfm b/demos/delphi/vcl/Dashboards/Editor/Unit_Main.dfm new file mode 100644 index 0000000..9cec154 --- /dev/null +++ b/demos/delphi/vcl/Dashboards/Editor/Unit_Main.dfm @@ -0,0 +1,100 @@ +object Form34: TForm34 + Left = 0 + Top = 0 + Caption = 'Form34' + ClientHeight = 594 + ClientWidth = 1154 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnCreate = FormCreate + PixelsPerInch = 96 + TextHeight = 13 + object BIVisual1: TBIVisual + Left = 24 + Top = 39 + Width = 945 + Height = 529 + TabOrder = 0 + Dashboards = < + item + Name = 'customers' + Items = < + item + Name = 'names' + Panel = 'names' + Text = 'CustomerID' + end + item + Name = 'customers' + Panel = 'customers' + Text = 'Item' + end> + end> + Data = < + item + Name = 'customer names' + end + item + Name = '#customer' + end + item + Name = 'customer items' + end> + Layouts = <> + Panels = < + item + Name = 'names' + Data = 'customer names' + Kind = List + Target = '#customer' + end + item + Name = 'customers' + Data = 'customer items' + Kind = Grid + end> + end + object Button1: TButton + Left = 8 + Top = 8 + Width = 75 + Height = 25 + Caption = 'Edit...' + TabOrder = 1 + OnClick = Button1Click + end + object Button2: TButton + Left = 120 + Top = 8 + Width = 75 + Height = 25 + Caption = 'Load...' + TabOrder = 2 + OnClick = Button2Click + end + object Memo1: TMemo + Left = 1000 + Top = 39 + Width = 112 + Height = 274 + Lines.Strings = ( + 'Country Population' + 'Spain 47500000' + 'USA 350000000' + 'Brazil 80000000') + TabOrder = 3 + end + object OpenDialog1: TOpenDialog + DefaultExt = '.json' + Filter = 'Template files|*.json' + Options = [ofHideReadOnly, ofFileMustExist, ofEnableSizing] + Title = 'Load Dashboard Template' + Left = 192 + Top = 104 + end +end diff --git a/demos/delphi/vcl/Dashboards/Editor/Unit_Main.pas b/demos/delphi/vcl/Dashboards/Editor/Unit_Main.pas new file mode 100644 index 0000000..4735fef --- /dev/null +++ b/demos/delphi/vcl/Dashboards/Editor/Unit_Main.pas @@ -0,0 +1,81 @@ +unit Unit_Main; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, + + BI.VCL.Editor.Template, BI.Dashboard.HTML, + BI.Dashboard, BI.VCL.Dashboard, BI.VCL.Dashboard.Chart, BI.VCL.Editor.Chart; + +type + TForm34 = class(TForm) + BIVisual1: TBIVisual; + Button1: TButton; + OpenDialog1: TOpenDialog; + Button2: TButton; + Memo1: TMemo; + procedure Button1Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure Button2Click(Sender: TObject); + private + { Private declarations } + + procedure LoadTemplate(const AFileName:String); + public + { Public declarations } + end; + +var + Form34: TForm34; + +implementation + +{$R *.dfm} + +uses + System.IOUtils, BI.Dashboard.Loader; + +function SampleTemplates:String; +var tmp : String; +begin + tmp:=GetCurrentDir; + + repeat + result:=TPath.Combine(tmp,'Templates'); + + if TDirectory.Exists(result) then + Exit + else + tmp:=TDirectory.GetParent(tmp); + until tmp=''; +end; + +procedure TForm34.Button1Click(Sender: TObject); +begin + TTemplateEditor.Edit(Self,BIVisual1.Template); +end; + +procedure TForm34.LoadTemplate(const AFileName:String); +begin + TTemplateLoader.FromJSONFile(AFileName,BIVisual1.Template); + + if BIVisual1.Dashboards.Count>0 then + BIVisual1.Dashboard:=BIVisual1.Dashboards[0]; +end; + +procedure TForm34.Button2Click(Sender: TObject); +begin + if OpenDialog1.Execute then + LoadTemplate(OpenDialog1.FileName); +end; + +procedure TForm34.FormCreate(Sender: TObject); +begin + OpenDialog1.InitialDir:=SampleTemplates; + + LoadTemplate(TPath.Combine(OpenDialog1.InitialDir,'customers.json')); +end; + +end. diff --git a/demos/delphi/vcl/Dashboards/Templates/customers.json b/demos/delphi/vcl/Dashboards/Templates/customers.json new file mode 100644 index 0000000..f6af6e5 --- /dev/null +++ b/demos/delphi/vcl/Dashboards/Templates/customers.json @@ -0,0 +1,45 @@ +{ + "main": "SQLite_Demo", + "data": [ + { + "name": "customer names", + "type": "query", + "data": "select distinct CustomerID, CompanyName from customers" + }, + { + "name": "#customer", + "type": "value", + "value": "\"FRANR\"" + }, + { + "name": "customer items", + "type": "record", + "data": "select * from customers where CustomerID=#customer" + } + ], + + "panels": [ + { + "name": "names", + "type": "list", + "data": "customer names", + "target": "#customer", + "display": "CompanyName" + }, + { + "name": "customers", + "type": "grid", + "data": "customer items" + } + ], + + "dashboards": [ + { + "name": "customers", + "panels": [ + { "name": "names" }, + { "name": "customers" } + ] + } + ] +} \ No newline at end of file diff --git a/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dpr b/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dpr new file mode 100644 index 0000000..6f230b1 --- /dev/null +++ b/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dpr @@ -0,0 +1,14 @@ +program BIGrid_Detail; + +uses + Vcl.Forms, + Unit_Grid_Detail in 'Unit_Grid_Detail.pas' {FormGridDetail}; + +{$R *.res} + +begin + Application.Initialize; + Application.MainFormOnTaskbar := True; + Application.CreateForm(TFormGridDetail, FormGridDetail); + Application.Run; +end. diff --git a/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dproj b/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dproj new file mode 100644 index 0000000..efcf862 --- /dev/null +++ b/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.dproj @@ -0,0 +1,528 @@ + + + {478447C1-A60B-449E-BD46-C11457027906} + 18.1 + VCL + BIGrid_Detail.dpr + True + Debug + Win32 + 1 + Application + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + true + Cfg_2 + true + true + + + System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + $(BDS)\bin\delphi_PROJECTICON.ico + BIGrid_Detail + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + $(BDS)\bin\default_app.manifest + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + true + 1033 + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;inetdb;VirtualTreesDR;emsedge;FireDACIBDriver;fmx;fmxdae;frx24;vclib;FireDACDBXDriver;dbexpress;IndyCore;FMXChartProTeeBI;vclx;dsnap;DataSnapCommon;emsclient;TeeBI;FireDACCommon;FMXTeeBI;bdertl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;VCLChartProTeeBI;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;VCLTeeBI;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;vcldbx;FixInsight_10_1;frxe24;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;frxDB24;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage) + + + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;VirtualTreesDR;emsedge;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;TeeBI;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;VCLChartProTeeBI;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;VCLTeeBI;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + true + true + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + true + true + + + + MainSource + + +
FormGridDetail
+ dfm +
+ + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Application + + + + BIGrid_Detail.dpr + + + + + + BIGrid_Detail.exe + true + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + Contents\MacOS + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + Contents\MacOS + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\ + 1 + + + ..\ + 1 + + + + + res\drawable-hdpi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + Contents + 1 + + + + + ..\ + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + Contents\Resources\StartUp\ + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + Contents\MacOS + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + 1 + + + 1 + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.res b/demos/delphi/vcl/Grid/Detail/BIGrid_Detail.res new file mode 100644 index 0000000000000000000000000000000000000000..2b29b132002c76612751ae8189a1b0b8a548790f GIT binary patch literal 59212 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 literal 0 HcmV?d00001 diff --git a/demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.dfm b/demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.dfm new file mode 100644 index 0000000..15b70d0 --- /dev/null +++ b/demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.dfm @@ -0,0 +1,64 @@ +object FormGridDetail: TFormGridDetail + Left = 0 + Top = 0 + Caption = 'TeeBI - Automatic Detail Grid' + ClientHeight = 641 + ClientWidth = 1028 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + Position = poOwnerFormCenter + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object BIGrid1: TBIGrid + Left = 0 + Top = 62 + Width = 1028 + Height = 579 + Align = alClient + UseDockManager = False + ParentBackground = False + ParentColor = False + TabOrder = 0 + ExplicitLeft = 360 + ExplicitTop = 280 + ExplicitWidth = 320 + ExplicitHeight = 120 + Origin = '|restaurants|restaurants' + end + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 1028 + Height = 62 + Align = alTop + BevelOuter = bvNone + TabOrder = 1 + object Label1: TLabel + Left = 24 + Top = 25 + Width = 84 + Height = 13 + Caption = 'Show detail data:' + end + object RGDetail: TRadioGroup + Left = 128 + Top = 7 + Width = 321 + Height = 43 + Columns = 3 + ItemIndex = 1 + Items.Strings = ( + 'None' + 'Address Coord' + 'Grades') + TabOrder = 0 + OnClick = RGDetailClick + end + end +end diff --git a/demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.pas b/demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.pas new file mode 100644 index 0000000..ec73ccb --- /dev/null +++ b/demos/delphi/vcl/Grid/Detail/Unit_Grid_Detail.pas @@ -0,0 +1,60 @@ +unit Unit_Grid_Detail; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, BI.Data, BI.VCL.DataControl, BI.VCL.Grid, + Vcl.StdCtrls, Vcl.ExtCtrls; + +type + TFormGridDetail = class(TForm) + BIGrid1: TBIGrid; + Panel1: TPanel; + Label1: TLabel; + RGDetail: TRadioGroup; + procedure FormShow(Sender: TObject); + procedure RGDetailClick(Sender: TObject); + private + { Private declarations } + + procedure ShowDetail(const AData:TDataItem); + public + { Public declarations } + end; + +var + FormGridDetail: TFormGridDetail; + +implementation + +{$R *.dfm} + +uses + BI.VCL.Grid.DBGrid; + +procedure TFormGridDetail.FormShow(Sender: TObject); +begin + RGDetail.ItemIndex:=1; + RGDetailClick(Self); +end; + +procedure TFormGridDetail.RGDetailClick(Sender: TObject); +begin + case RGDetail.ItemIndex of + 1: ShowDetail(BIGrid1.Data['address']['coord']); + 2: ShowDetail(BIGrid1.Data['grades']); + else + ShowDetail(nil); + end; +end; + +procedure TFormGridDetail.ShowDetail(const AData:TDataItem); +var Grid : TBIDBGrid; +begin + Grid:=(BIGrid1.Plugin.GetObject as TBIDBGrid); + + Grid.Detail:=AData; +end; + +end. diff --git a/demos/delphi/vcl/Import/Import_ByCode.dfm b/demos/delphi/vcl/Import/Import_ByCode.dfm index 563ee93..0a5565d 100644 --- a/demos/delphi/vcl/Import/Import_ByCode.dfm +++ b/demos/delphi/vcl/Import/Import_ByCode.dfm @@ -46,7 +46,10 @@ object ByCode: TByCode Width = 75 Height = 25 Caption = '&Close' + Default = True + ModalResult = 1 TabOrder = 0 + OnClick = Button4Click end end end @@ -88,10 +91,6 @@ object ByCode: TByCode TabOrder = 2 object TabBIGrid: TTabSheet Caption = 'Data' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object BIGrid1: TBIGrid Left = 0 Top = 0 @@ -107,18 +106,10 @@ object ByCode: TByCode object TabStructure: TTabSheet Caption = 'Structure' ImageIndex = 1 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 end object TabSource: TTabSheet Caption = 'Source Samples' ImageIndex = 2 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object PageExamples: TPageControl Left = 0 Top = 0 @@ -129,10 +120,6 @@ object ByCode: TByCode TabOrder = 0 object TabCSV: TTabSheet Caption = 'CSV' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object MemoCSV: TMemo Left = 0 Top = 0 @@ -150,10 +137,6 @@ object ByCode: TByCode object TabJSON: TTabSheet Caption = 'JSON' ImageIndex = 1 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object MemoJSON: TMemo Left = 0 Top = 0 @@ -192,10 +175,6 @@ object ByCode: TByCode object TabXML: TTabSheet Caption = 'XML' ImageIndex = 2 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object MemoXML: TMemo Left = 0 Top = 0 @@ -225,10 +204,6 @@ object ByCode: TByCode object TabDatabase: TTabSheet Caption = 'Database' ImageIndex = 3 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object DBGrid1: TDBGrid Left = 0 Top = 0 diff --git a/demos/delphi/vcl/Import/Import_ByCode.pas b/demos/delphi/vcl/Import/Import_ByCode.pas index dbdb3cf..da7c14a 100644 --- a/demos/delphi/vcl/Import/Import_ByCode.pas +++ b/demos/delphi/vcl/Import/Import_ByCode.pas @@ -35,6 +35,7 @@ TByCode = class(TForm) procedure LBFormatClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); + procedure Button4Click(Sender: TObject); private { Private declarations } @@ -66,6 +67,11 @@ implementation { TByCode } // Helper method to create a TDataItem from an array of TDataItem +procedure TByCode.Button4Click(Sender: TObject); +begin + Close; +end; + function TByCode.CreateData(const AName:String; const AData:TDataArray):TDataItem; begin result:=TBISource.FromData(AData); diff --git a/demos/delphi/vcl/MapReduce/BI_MapReduce.dpr b/demos/delphi/vcl/MapReduce/BI_MapReduce.dpr index ca2dcfb..ef8357f 100644 --- a/demos/delphi/vcl/MapReduce/BI_MapReduce.dpr +++ b/demos/delphi/vcl/MapReduce/BI_MapReduce.dpr @@ -2,8 +2,7 @@ program BI_MapReduce; uses Vcl.Forms, - Unit_Main in 'Unit_Main.pas' {DemoForm}, - BI.MapReduce in '..\..\..\..\..\Sources\BI.MapReduce.pas'; + Unit_Main in 'Unit_Main.pas' {DemoForm}; {$R *.res} diff --git a/demos/delphi/vcl/MapReduce/BI_MapReduce.dproj b/demos/delphi/vcl/MapReduce/BI_MapReduce.dproj index 26d7839..b0a83e0 100644 --- a/demos/delphi/vcl/MapReduce/BI_MapReduce.dproj +++ b/demos/delphi/vcl/MapReduce/BI_MapReduce.dproj @@ -77,6 +77,9 @@ true + 1033 + c:\root\teebee\sources;c:\root\teebee\sources\vcl;$(DCC_UnitSearchPath) + true true true false @@ -99,7 +102,6 @@
DemoForm
dfm - Cfg_2 Base @@ -120,6 +122,15 @@ BI_MapReduce.dpr + + File e:\Program Files (x86)\FastReports\LibD23\dclfrx23.bpl not found + File e:\Program Files (x86)\FastReports\LibD23\dclfrxDB23.bpl not found + File e:\Program Files (x86)\FastReports\LibD23\dclfrxe23.bpl not found + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + @@ -514,6 +525,7 @@ + diff --git a/demos/delphi/vcl/MapReduce/Unit_Main.dfm b/demos/delphi/vcl/MapReduce/Unit_Main.dfm index 8893d2d..f4fdb2b 100644 --- a/demos/delphi/vcl/MapReduce/Unit_Main.dfm +++ b/demos/delphi/vcl/MapReduce/Unit_Main.dfm @@ -64,6 +64,10 @@ object DemoForm: TDemoForm TabOrder = 1 object TabSheet1: TTabSheet Caption = 'Output' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object BIGrid1: TBIGrid Left = 0 Top = 0 diff --git a/demos/delphi/vcl/MapReduce/Unit_Main.pas b/demos/delphi/vcl/MapReduce/Unit_Main.pas index e4159b7..066f740 100644 --- a/demos/delphi/vcl/MapReduce/Unit_Main.pas +++ b/demos/delphi/vcl/MapReduce/Unit_Main.pas @@ -137,6 +137,8 @@ procedure TDemoForm.FormCreate(Sender: TObject); BIGrid2.Data:=Movies; LabelRows.Caption:=Movies.Count.ToString; + + PageControl1.ActivePage:=TabSheet1; end; procedure TDemoForm.FormDestroy(Sender: TObject); diff --git a/demos/delphi/vcl/Master-Detail/Master_Detail_Unit.dfm b/demos/delphi/vcl/Master-Detail/Master_Detail_Unit.dfm index 612d1bc..56b6d77 100644 --- a/demos/delphi/vcl/Master-Detail/Master_Detail_Unit.dfm +++ b/demos/delphi/vcl/Master-Detail/Master_Detail_Unit.dfm @@ -192,6 +192,7 @@ object MasterDetailForm: TMasterDetailForm Top = 72 end object Detail: TBIDataset + AfterOpen = DetailAfterRefresh AfterRefresh = DetailAfterRefresh Master = Master RowNumbers = False diff --git a/demos/delphi/vcl/Search/Unit_DataSearch_Demo.pas b/demos/delphi/vcl/Search/Unit_DataSearch_Demo.pas index ce852e1..b4867d7 100644 --- a/demos/delphi/vcl/Search/Unit_DataSearch_Demo.pas +++ b/demos/delphi/vcl/Search/Unit_DataSearch_Demo.pas @@ -15,7 +15,7 @@ interface // TeeBI units used in this example - BI.Data, BI.Persist, BI.Data.Search, + BI.Data, BI.Persist, BI.Data.Search, BI.Compare, BI.VCL.Grid, BI.VCL.DataManager, BI.Dataset, BI.DataSource, BI.Arrays, BI.VCL.DataControl; @@ -66,6 +66,7 @@ TFormSearchDemo = class(TForm) OldBack : TColor; OldStyle : TFontStyles; + procedure SearchFinished(const AIndex:TCursorIndex); procedure SetLabelFound; procedure SetSearch(const AIndex:TCursorIndex); procedure SetupHighlight; @@ -244,19 +245,22 @@ procedure TFormSearchDemo.FormCreate(Sender: TObject); // When a search finishes, show results at BIGrid and count at label. // This is necessary for "background thread" searches. - Search.OnFinished:=procedure(const AIndex:TCursorIndex) - begin - TThread.Synchronize(nil,procedure - begin - SetSearch(AIndex); - end); - end; + Search.OnFinished:=SearchFinished; DataSource1.DataSet:=BIDataset1; SetupHighlight; end; +// This event is called when Search task finishes +procedure TFormSearchDemo.SearchFinished(const AIndex:TCursorIndex); +begin + TThread.Synchronize(nil,procedure + begin + SetSearch(AIndex); + end); +end; + // Prepare grid events for cell highlighting procedure TFormSearchDemo.SetupHighlight; var Grid : TBIDBGrid; diff --git a/demos/lazarus/BIGrid/project1.lps b/demos/lazarus/BIGrid/project1.lps index d3bb0a5..2dd1689 100644 --- a/demos/lazarus/BIGrid/project1.lps +++ b/demos/lazarus/BIGrid/project1.lps @@ -4,13 +4,14 @@ - + - + - + + @@ -19,11 +20,9 @@ - - - - - + + + @@ -55,11 +54,10 @@ - + - @@ -71,11 +69,10 @@ - + - @@ -87,144 +84,290 @@ + - - + - - + - - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + + - - + + - - + + - - + + - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + + - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/demos/lazarus/BIGrid/unit1.lfm b/demos/lazarus/BIGrid/unit1.lfm index 545013a..b2a7f4c 100644 --- a/demos/lazarus/BIGrid/unit1.lfm +++ b/demos/lazarus/BIGrid/unit1.lfm @@ -1,9 +1,31 @@ object Form1: TForm1 - Left = 238 + Left = 335 Height = 623 - Top = 254 + Top = 135 Width = 1020 - Caption = 'Form1' + Caption = 'TeeBI for Lazarus - BIGrid Example' + ClientHeight = 623 + ClientWidth = 1020 OnCreate = FormCreate - LCLVersion = '1.7' + Position = poOwnerFormCenter + LCLVersion = '1.6.0.4' + object Panel1: TPanel + Left = 0 + Height = 50 + Top = 0 + Width = 1020 + Align = alTop + ClientHeight = 50 + ClientWidth = 1020 + TabOrder = 0 + object Button1: TButton + Left = 14 + Height = 25 + Top = 13 + Width = 75 + Caption = '&Data...' + OnClick = Button1Click + TabOrder = 0 + end + end end diff --git a/demos/lazarus/BIGrid/unit1.pas b/demos/lazarus/BIGrid/unit1.pas index 610ba22..b785e3e 100644 --- a/demos/lazarus/BIGrid/unit1.pas +++ b/demos/lazarus/BIGrid/unit1.pas @@ -5,13 +5,16 @@ interface uses - Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, - BI_VCL_Grid, BI_Persist; + Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ExtCtrls, + StdCtrls, BI_VCL_Grid, BI_Persist; { TForm1 } type TForm1 = class(TForm) + Button1: TButton; + Panel1: TPanel; + procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { private declarations } @@ -28,6 +31,9 @@ implementation {$R *.lfm} +uses + BI_VCL_DataSelect; + { TForm1 } procedure TForm1.FormCreate(Sender: TObject); @@ -39,5 +45,10 @@ procedure TForm1.FormCreate(Sender: TObject); Grid.Data:=TStore.Load('BISamples','SQLite_Demo')['Products']; end; +procedure TForm1.Button1Click(Sender: TObject); +begin + TDataSelector.Choose(Self,Grid); +end; + end. diff --git a/server/Apache/VCL/BI.Web.ApacheContext.pas b/server/Apache/VCL/BI.Web.ApacheContext.pas new file mode 100644 index 0000000..49d244b --- /dev/null +++ b/server/Apache/VCL/BI.Web.ApacheContext.pas @@ -0,0 +1,146 @@ +unit BI.Web.ApacheContext; + +interface + +uses + System.Classes, + Web.ApacheHTTP, + BI.Web.Common; + +type + TBIApacheContext=class(TBIWebContext) + public + procedure Finish; + function FormParams: String; override; + + class function Process(const BIWeb:TBIWebCommon; + const ARequest: TApacheRequest; + const AResponse: TApacheResponse):Boolean; static; + + function Params:TStrings; override; + function PeerIP:String; + function ResponseSize:Int64; override; + procedure ReturnFile(const AFile:String); override; + end; + +implementation + +uses + System.SysUtils, + System.IOUtils, BI.DataSource, BI.Persist, Web.HttpApp; + +{ TBIApacheContext } + +procedure TBIApacheContext.Finish; +var tmp : TApacheResponse; +begin + tmp:=TApacheResponse(ResponseInfo); + tmp.Content:=ContentText; + + if ContentType='' then + if (ContentText<>'') and (ResponseStream=nil) then + ContentType:='text/html; charset=ISO-8859-1'; + + tmp.ContentType:=AnsiString(ContentType); + tmp.ContentStream:=ResponseStream; +end; + +function TBIApacheContext.FormParams: String; +begin + result:=TApacheRequest(RequestInfo).ContentFields.Text; //FormParams; +end; + +function TBIApacheContext.Params: TStrings; +var tmp : TApacheRequest; +begin + tmp:=TApacheRequest(RequestInfo); + + if tmp.MethodType=TMethodType.mtGet then + result:=tmp.QueryFields + else + result:=tmp.ContentFields; +end; + +function TBIApacheContext.PeerIP: String; +begin + result:=String(TApacheRequest(RequestInfo).RemoteAddr); +end; + +class function TBIApacheContext.Process(const BIWeb: TBIWebCommon; + const ARequest: TApacheRequest; const AResponse: TApacheResponse):Boolean; +var tmp : TBIApacheContext; +begin + tmp:=TBIApacheContext.Create; + try + tmp.ResponseInfo:=AResponse; + tmp.RequestInfo:=ARequest; + + //tmp.ContentText:='Ini: '+TBIRegistry.IniFile; + + {$IFDEF DEBUGREQUEST} + tmp.ContentText:=ARequest.URL; + + if ARequest.MethodType=TMethodType.mtGet then + tmp.ContentText:=tmp.ContentText+' get' + else + if ARequest.MethodType=TMethodType.mtPost then + tmp.ContentText:=tmp.ContentText+' post'; + + tmp.ContentText:=tmp.ContentText+' '+ARequest.Query+' '+ARequest.PathInfo; + {$ENDIF} + + {$IFDEF IIS_STATIC} + // Pending: We cannot return static files yet + if ARequest.URL<>'/' then + BIWeb.ProcessFile(String(ARequest.URL),tmp) + else + {$ENDIF} + + if ARequest.MethodType=TMethodType.mtGet then + BIWeb.ProcessGet(tmp) + else + if ARequest.MethodType=TMethodType.mtPost then + BIWeb.ProcessPost(tmp); + + tmp.Finish; + + result:=True; + finally + tmp.Free; + end; +end; + +function TBIApacheContext.ResponseSize: Int64; +begin + result:=TApacheResponse(ResponseInfo).ContentLength; + + if result=-1 then + if ResponseStream<>nil then + result:=ResponseStream.Size + else + result:=Length(ContentText); +end; + +procedure TBIApacheContext.ReturnFile(const AFile: String); +var //Enable : Boolean; + tmp : TApacheResponse; + tmpStream : TStream; +begin + tmp:=TApacheResponse(ResponseInfo); + +// if ContentType='' then +// ContentType:=tmp.HTTPServer.MIMETable.GetFileMIMEType(AFile); + + tmp.ContentLength:=TBIFileSource.GetFileSize(AFile); + + tmpStream:=TFileStream.Create(AFile,fmOpenRead and fmShareDenyWrite); + tmp.ContentStream:=tmpStream; +// tmp.ContentType:='application/x-zip-compressed'; + tmp.SetCustomHeader('Content-Disposition','filename='+ExtractFilename(AFile)); + +// tmp.WriteHeader; +// Enable:=not (IContext.Connection.IOHandler is TIdSSLIOHandlerSocketBase); +// IContext.Connection.IOHandler.WriteFile(AFile, Enable); +end; + +end. diff --git a/server/Apache/VCL/BIWeb.ModuleUnit.Apache.dfm b/server/Apache/VCL/BIWeb.ModuleUnit.Apache.dfm new file mode 100644 index 0000000..72e15e6 --- /dev/null +++ b/server/Apache/VCL/BIWeb.ModuleUnit.Apache.dfm @@ -0,0 +1,14 @@ +object WebModule1: TWebModule1 + OldCreateOrder = False + OnCreate = WebModuleCreate + OnDestroy = WebModuleDestroy + Actions = < + item + Default = True + Name = 'DefaultHandler' + PathInfo = '/' + OnAction = WebModule1DefaultHandlerAction + end> + Height = 230 + Width = 415 +end diff --git a/server/Apache/VCL/BIWeb.ModuleUnit.Apache.pas b/server/Apache/VCL/BIWeb.ModuleUnit.Apache.pas new file mode 100644 index 0000000..1573b06 --- /dev/null +++ b/server/Apache/VCL/BIWeb.ModuleUnit.Apache.pas @@ -0,0 +1,94 @@ +unit BIWeb.ModuleUnit.Apache; + +interface + +uses System.SysUtils, System.Classes, Web.ApacheHTTP, Web.HttpApp, + BI.Web, BI.Web.Common, BI.Web.ApacheContext, BI.Web.AllData, BI.Persist; + +type + TWebModule1 = class(TWebModule) + procedure WebModule1DefaultHandlerAction(Sender: TObject; + Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); + procedure WebModuleCreate(Sender: TObject); + procedure WebModuleDestroy(Sender: TObject); + private + { Private declarations } + BIWeb : TBIWebCommon; + Data : TAllData; + History : TBIWebHistory; + + procedure AddHistory(const AContext:TBIWebContext; + const Command:String; + const Tag:String; + const Success:Boolean; + const Millisec:Integer; const Size:Int64); + procedure Log(const S:String); + public + { Public declarations } + end; + +var + WebModuleClass: TComponentClass = TWebModule1; + +implementation + +{%CLASSGROUP 'Vcl.Controls.TControl'} + +{$R *.dfm} + +procedure TWebModule1.WebModule1DefaultHandlerAction(Sender: TObject; + Request: TWebRequest; Response: TWebResponse; var Handled: Boolean); +begin + Handled:=TBIApacheContext.Process(BIWeb,TApacheRequest(Request),TApacheResponse(Response)); +end; + +procedure TWebModule1.AddHistory(const AContext:TBIWebContext; + const Command:String; + const Tag:String; + const Success:Boolean; + const Millisec:Integer; const Size:Int64); +var tmpNow : TDateTime; + IP: String; +begin + tmpNow:=Now; + + IP:=TBIApacheContext(AContext).PeerIP; + + History.Add(tmpNow,IP,Command,Tag,Success,Millisec,Size); + + if not Success then + Log(DateTimeToStr(Now)+' '+IP+' '+Command+' '+Tag); +end; + +procedure TWebModule1.WebModuleCreate(Sender: TObject); +begin + TBIRegistry.UseRegistry:=False; // Use inifile + TBIRegistry.IniFile:='C:\apache\TeeBI.ini'; // <-- pending: use httpd.conf ? + + BIWeb:=TBIWebCommon.Create; + + History:=TBIWebHistory.Create; + History.Name:='History'; + + Data:=TAllData.Create; + + BIWeb.Logs.History:=History; + BIWeb.Data:=Data; + BIWeb.Logs.AddHistory:=AddHistory; + + Log('Started: '+DateTimeToStr(Now)); +end; + +procedure TWebModule1.Log(const S:String); +begin +end; + +procedure TWebModule1.WebModuleDestroy(Sender: TObject); +begin + Data.Free; + History.Free; + + BIWeb.Free; +end; + +end. diff --git a/server/Apache/VCL/BIWeb_Apache.dpr b/server/Apache/VCL/BIWeb_Apache.dpr new file mode 100644 index 0000000..9afea3c --- /dev/null +++ b/server/Apache/VCL/BIWeb_Apache.dpr @@ -0,0 +1,48 @@ +library BIWeb_Apache; + +uses + {$IFDEF MSWINDOWS} + Winapi.ActiveX, + System.Win.ComObj, + {$ENDIF } + Web.WebBroker, + Web.HTTPD24Impl, + BIWeb.ModuleUnit.Apache in 'BIWeb.ModuleUnit.Apache.pas' {WebModule1: TWebModule}, + BI.Web.AllData in '..\..\BI.Web.AllData.pas', + BI.Web.Common in '..\..\BI.Web.Common.pas', + BI.Web.ApacheContext in 'BI.Web.ApacheContext.pas'; + +{$R *.res} + +// httpd.conf entries: +// +(* + LoadModule teebi_module modules/mod_teebi.dll + + + SetHandler mod_teebi-handler + +*) +// +// These entries assume that the output directory for this project is the apache/modules directory. +// +// httpd.conf entries should be different if the project is changed in these ways: +// 1. The TApacheModuleData variable name is changed +// 2. The project is renamed. +// 3. The output directory is not the apache/modules directory +// + +// Declare exported variable so that Apache can access this module. +var + GModuleData: TApacheModuleData; +exports + GModuleData name 'teebi_module'; + +begin +{$IFDEF MSWINDOWS} + CoInitFlags := COINIT_MULTITHREADED; +{$ENDIF} + Application.Initialize; + Application.WebModuleClass := WebModuleClass; + Application.Run; +end. diff --git a/server/Apache/VCL/BIWeb_Apache.dproj b/server/Apache/VCL/BIWeb_Apache.dproj new file mode 100644 index 0000000..94e7617 --- /dev/null +++ b/server/Apache/VCL/BIWeb_Apache.dproj @@ -0,0 +1,474 @@ + + + {273963C5-F0D7-4A63-9A88-7121F77AF0B7} + 18.1 + VCL + BIWeb_Apache.dpr + True + Debug + Win32 + 1 + Library + + + true + + + true + Base + true + + + true + Base + true + + + true + Base + true + + + true + Cfg_1 + true + true + + + true + Base + true + + + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + c:\root\teechartvcl\sources9\vcl;$(DCC_UnitSearchPath) + 1027 + $(BDS)\bin\delphi_PROJECTICNS.icns + vcltee;System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace) + true + $(BDS)\bin\delphi_PROJECTICON.ico + BIWeb_Apache + .\$(Platform)\$(Config) + .\$(Platform)\$(Config) + false + false + false + false + false + + + true + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;svnui;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;svn;Intraweb;DBXOracleDriver;inetdb;VirtualTreesDR;emsedge;FireDACIBDriver;fmx;fmxdae;frx24;vclib;FireDACDBXDriver;dbexpress;IndyCore;FMXChartProTeeBI;vclx;dsnap;DataSnapCommon;emsclient;TeeBI;FireDACCommon;FMXTeeBI;bdertl;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;VCLChartProTeeBI;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;VCLTeeBI;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;vcldbx;FixInsight_10_1;frxe24;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;frxDB24;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage) + 1033 + Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) + CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= + + + DBXSqliteDriver;RESTComponents;DataSnapServerMidas;DBXDb2Driver;DBXInterBaseDriver;vclactnband;vclFireDAC;emsclientfiredac;DataSnapFireDAC;tethering;FireDACADSDriver;DBXMSSQLDriver;DatasnapConnectorsFreePascal;FireDACMSSQLDriver;vcltouch;vcldb;bindcompfmx;Intraweb;DBXOracleDriver;inetdb;VirtualTreesDR;emsedge;FireDACIBDriver;fmx;fmxdae;vclib;FireDACDBXDriver;dbexpress;IndyCore;vclx;dsnap;DataSnapCommon;emsclient;TeeBI;FireDACCommon;RESTBackendComponents;DataSnapConnectors;VCLRESTComponents;soapserver;vclie;bindengine;DBXMySQLDriver;FireDACOracleDriver;CloudService;FireDACMySQLDriver;DBXFirebirdDriver;FireDACCommonODBC;FireDACCommonDriver;VCLChartProTeeBI;DataSnapClient;inet;bindcompdbx;IndyIPCommon;vcl;DBXSybaseASEDriver;IndyIPServer;IndySystem;FireDACDb2Driver;dsnapcon;FireDACMSAccDriver;fmxFireDAC;FireDACInfxDriver;vclimg;FireDAC;emshosting;FireDACSqliteDriver;FireDACPgDriver;ibmonitor;FireDACASADriver;DBXOdbcDriver;FireDACTDataDriver;VCLTeeBI;soaprtl;DbxCommonDriver;ibxpress;DataSnapServer;xmlrtl;soapmidas;DataSnapNativeClient;fmxobj;vclwinx;ibxbindings;rtl;FireDACDSDriver;DbxClientDriver;DBXSybaseASADriver;CustomIPTransport;vcldsnap;bindcomp;appanalytics;DBXInformixDriver;IndyIPClient;bindcompvcl;dbxcds;VclSmp;adortl;FireDACODBCDriver;DataSnapIndy10ServerTransport;dsnapxml;DataSnapProviderClient;dbrtl;inetdbxpress;FireDACMongoDBDriver;IndyProtocols;fmxase;$(DCC_UsePackage) + + + DEBUG;$(DCC_Define) + true + false + true + true + true + + + true + 1033 + (None) + false + + + false + RELEASE;$(DCC_Define) + 0 + 0 + + + + MainSource + + +
WebModule1
+ TWebModule +
+ + + + + Cfg_2 + Base + + + Base + + + Cfg_1 + Base + +
+ + Delphi.Personality.12 + Library + + + + BIWeb_Apache.dpr + + + Embarcadero C++Builder Office 2000 Servers Package + Embarcadero C++Builder Office XP Servers Package + Microsoft Office 2000 Sample Automation Server Wrapper Components + Microsoft Office XP Sample Automation Server Wrapper Components + + + + + + BIWeb_Apache.dll + true + + + + + 0 + .dll;.bpl + + + 1 + .dylib + + + + + Contents\Resources + 1 + + + + + classes + 1 + + + + + Contents\MacOS + 0 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-xxhdpi + 1 + + + + + library\lib\mips + 1 + + + + + 1 + + + 1 + + + 0 + + + 1 + + + 1 + + + library\lib\armeabi-v7a + 1 + + + 1 + + + + + 0 + + + 1 + .framework + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + ..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF + 1 + + + + + 1 + + + 1 + + + 1 + + + + + + library\lib\armeabi + 1 + + + + + 0 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + res\drawable-normal + 1 + + + + + res\drawable-xhdpi + 1 + + + + + res\drawable-large + 1 + + + + + 1 + + + 1 + + + 1 + + + + + + res\drawable-hdpi + 1 + + + + + library\lib\armeabi-v7a + 1 + + + + + + + 1 + + + 1 + + + 1 + + + + + res\values + 1 + + + + + res\drawable-small + 1 + + + + + res\drawable + 1 + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + + + res\drawable + 1 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + library\lib\armeabi-v7a + 1 + + + + + 0 + .bpl + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + 1 + .dylib + + + + + res\drawable-mdpi + 1 + + + + + res\drawable-xlarge + 1 + + + + + res\drawable-ldpi + 1 + + + + + + + + + + + + + + True + False + + + 12 + + + + +
diff --git a/server/Apache/VCL/BIWeb_Apache.res b/server/Apache/VCL/BIWeb_Apache.res new file mode 100644 index 0000000000000000000000000000000000000000..d070105828b2d264cf07a0a26a36211fdd78c525 GIT binary patch literal 57492 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 literal 0 HcmV?d00001 diff --git a/server/BI.Web.AllData.pas b/server/BI.Web.AllData.pas index 1b1e72b..e976c93 100644 --- a/server/BI.Web.AllData.pas +++ b/server/BI.Web.AllData.pas @@ -26,11 +26,11 @@ TAllData=class function Find(const AData:String):TDataItem; - function GetDataOrigins(const AItems: TDataItems): TStringDynArray; - function GetData(const AItems:TDataItems):TStringDynArray; overload; + function GetDataOrigins(const AItems: TDataItems): TStringArray; + function GetData(const AItems:TDataItems):TStringArray; overload; function GetData:String; overload; - function GetDataArray: TStringDynArray; + function GetDataArray: TStringArray; function GetDefinition(const AName:String): String; @@ -115,7 +115,7 @@ function TAllData.AllData: TDataItem; end; var H,t : Integer; - Data : TStringDynArray; + Data : TStringArray; begin result:=TDataItem.Create(True); result.Name:=FStore; @@ -140,7 +140,7 @@ function TAllData.AllData: TDataItem; ProcessData(Data[t],t); end; -function TAllData.GetDataArray: TStringDynArray; +function TAllData.GetDataArray: TStringArray; begin result:=TStore.AllData(FStore); end; @@ -161,7 +161,7 @@ function TAllData.GetDefinition(const AName:String): String; function TAllData.GetData: String; var H,t : Integer; - Data : TStringDynArray; + Data : TStringArray; begin result:=''; @@ -178,7 +178,7 @@ function TAllData.GetData: String; end; end; -function TAllData.GetData(const AItems: TDataItems): TStringDynArray; +function TAllData.GetData(const AItems: TDataItems): TStringArray; var t : Integer; begin SetLength(result,AItems.Count); @@ -187,7 +187,7 @@ function TAllData.GetData(const AItems: TDataItems): TStringDynArray; result[t]:=AItems[t].Name; end; -function TAllData.GetDataOrigins(const AItems: TDataItems): TStringDynArray; +function TAllData.GetDataOrigins(const AItems: TDataItems): TStringArray; var t : Integer; begin SetLength(result,AItems.Count); diff --git a/server/BI.Web.Common.pas b/server/BI.Web.Common.pas index 45a0a36..84d57f0 100644 --- a/server/BI.Web.Common.pas +++ b/server/BI.Web.Common.pas @@ -209,7 +209,8 @@ implementation uses System.SysUtils, System.IOUtils, System.Types, BI.Data.SQL, BI.Data.Html, BI.Languages.English, - BI.Dashboard, BI.Dashboard.HTML, BI.Data.Expressions; + BI.Dashboard, BI.Dashboard.HTML, BI.Dashboard.Loader, + BI.Data.Expressions; Constructor TBIWebCommon.Create; begin @@ -1159,9 +1160,9 @@ procedure TBIWebCommon.DataLink(const Sender:TBIExport; const AData:TDataItem; c function TBIWebCommon.ProcessDashboard(const AContext: TBIWebContext):Boolean; - function TitleOrName(const APanel:TBIPanel):String; + function TitleOrName(const APanel:TCustomBIPanel):String; begin - result:=APanel['title']; + result:=APanel.Title; if result='' then result:=APanel.Name; @@ -1179,8 +1180,10 @@ function TBIWebCommon.ProcessDashboard(const AContext: TBIWebContext):Boolean; tmpIndex : Integer; begin - tmpTemplate:=TBITemplate.FromJSON(AText); + tmpTemplate:=TBITemplate.Create(nil); try + TTemplateLoader.FromJSON(AText,tmpTemplate); + tmpDash:=AContext.Params.Values['dashboard']; if tmpDash='' then @@ -1593,7 +1596,7 @@ TDataDefinitionAccess=class(TDataDefinition); procedure TImportScheduler.AddAll; var t,L : Integer; - tmp : TStringDynArray; + tmp : TStringArray; tmpDef : TDataDefinition; begin tmp:=TStore.AllData(FStore); diff --git a/server/fmx/BI_FMX_Web.res b/server/fmx/BI_FMX_Web.res index 3e1e1051e24e3e0a161e112ce929dd2618b24067..3179d9738a56489b4a3f408246710b728c381e85 100644 GIT binary patch delta 752 zcmbu7zfQw25Qo)D3_*pN(Uke9|0cFnDuzm^69WilJGMonw27KPRUwo&U?~rR#L7c3 z@-8g66$2n;fQ~+Y^5?tzy+3wdpE}RIarbTKWq#e_6mBtQg@fwNSA7Ty8I(mLmuWgb8D2mkgb?QSLr zlSXN1gjK=qjRonb1x-1}lnSqyUb{D6|9k7QUClN1R5}KN83hgJoPg0P1sf~NHP^9Y zavSwAX_pfpCvlp@Ah9FBDQgrcVGKxSv5zgbI@v}}aJySN>=R8W7;jh@xszbjL<`{3 mTY)tZT5VTrue True - + BI_VCL_Web.exe true - - - 0 - .dll;.bpl - + 1 - .dylib - - - Contents\MacOS - 1 - .dylib 1 - .dylib - - - 1 - .dylib @@ -262,19 +247,22 @@ + + 1 + + + 1 + 0 - + 1 Contents\MacOS 1 - - 1 - library\lib\armeabi-v7a 1 @@ -325,12 +313,7 @@ 1 - - - library\lib\x86 - 1 - - + 1 @@ -413,11 +396,11 @@ - ../ + ..\ 1 - ../ + ..\ 1 @@ -441,7 +424,7 @@ - ../ + ..\ 1 @@ -564,18 +547,34 @@ 1 - + + + 0 + .dll;.bpl + 1 + .dylib + + + Contents\MacOS + 1 + .dylib 1 + .dylib + + + 1 + .dylib + diff --git a/server/vcl/BI_VCL_Web.res b/server/vcl/BI_VCL_Web.res index b80406b5bc5a48858fef54dc6f6bffaee5ed9579..134c556981a71bd84bd16c82be7c9a65899d051d 100644 GIT binary patch delta 752 zcmbu7zfQw25Qo)D3_*pN(Uke9|0cFnDuzm^69WilJGMonw27KPRUwo&U?~rR#L7c3 z@-8g66$2n;fQ~+Y^5?tzy+3wdpE}RIarbTKWq#e_6mBtQg@fwNSA7Ty8I(mLmuWgb8D2mkgb?QSLr zlSXN1gjK=qjRonb1x-1}lnSqyUb{D6|9k7QUClN1R5}KN83hgJoPg0P1sf~NHP^9Y zavSwAX_pfpCvlp@Ah9FBDQgrcVGKxSv5zgbI@v}}aJySN>=R8W7;jh@xszbjL<`{3 mTY)tZT5V; + {$ENDIF} + TDateTimeArray=Array of TDateTime; TInt32Array=Array of Integer; @@ -355,8 +361,8 @@ TBooleanArrayHelper=record helper for TBooleanArray function Map:TBooleanMap; procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending:Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending:Boolean=True); overload; inline; function Stats:TBooleanStats; inline; procedure Swap(const A,B:TInteger); inline; procedure Zero(const Value:Boolean=False); @@ -386,8 +392,8 @@ TTextArrayHelper=record helper for TTextArray function MaxLength:Integer; procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending:Boolean=True; const IgnoreCase:Boolean=False); overload; procedure Sort(const Ascending,IgnoreCase:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending:Boolean=True; const IgnoreCase:Boolean=False); overload; inline; function SortedFind(const Value: String; out Exists:Boolean; const IgnoreCase:Boolean): TNativeInteger; function Stats:TTextStats; inline; procedure Swap(const A,B:TInteger); inline; @@ -415,8 +421,8 @@ TDateTimeArrayHelper=record helper for TDateTimeArray function Minimum:TDateTime; procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending:Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending:Boolean=True); overload; inline; function SortedFind(const Value:TDateTime; out Exists:Boolean):TNativeInteger; function Stats:TDateTimeStats; function StdDeviation(const Mean:TDateTime):TFloat; @@ -451,8 +457,8 @@ TInt32ArrayHelper=record helper for TInt32Array procedure RemoveValue(const Value:Integer); procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending:Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending:Boolean=True); overload; function SortedFind(const Value: Integer; out Exists:Boolean):TNativeInteger; function Stats:TInt32Stats; function StdDeviation(const Mean:TFloat):TFloat; @@ -489,8 +495,8 @@ TInt64ArrayHelper=record helper for TInt64Array procedure RemoveValue(const Value:Int64); procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending:Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending:Boolean=True); overload; function SortedFind(const Value: Int64; out Exists:Boolean):TNativeInteger; function Stats:TInt64Stats; function StdDeviation(const Mean:TFloat):TFloat; @@ -525,8 +531,8 @@ TSingleArrayHelper=record helper for TSingleArray procedure Normalize(const Mean:Single); procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending: Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending: Boolean=True); overload; inline; function SortedFind(const Value: Single; out Exists:Boolean):TNativeInteger; function Stats:TSingleStats; function StdDeviation(const Mean:Single):Single; @@ -561,8 +567,8 @@ TDoubleArrayHelper=record helper for TDoubleArray procedure Normalize(const Mean:Double); procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending: Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending: Boolean=True); overload; inline; function SortedFind(const Value: Double; out Exists:Boolean):TNativeInteger; function Stats:TDoubleStats; function StdDeviation(const Mean:Double):Double; @@ -598,8 +604,8 @@ TExtendedArrayHelper=record helper for TExtendedArray procedure Normalize(const Mean:Extended); procedure Resize(const Count:TInteger); inline; procedure Reverse; inline; - procedure Sort(const Ascending: Boolean=True); overload; inline; procedure Sort(const Ascending:Boolean; const Swap:TSwapProc); overload; + procedure Sort(const Ascending: Boolean=True); overload; inline; function SortedFind(const Value: Extended; out Exists:Boolean):TNativeInteger; function Stats:TExtendedStats; function StdDeviation(const Mean:Extended):Extended; diff --git a/src/delphi/BI.Compare.pas b/src/delphi/BI.Compare.pas index 0749e96..c26e90b 100644 --- a/src/delphi/BI.Compare.pas +++ b/src/delphi/BI.Compare.pas @@ -66,17 +66,17 @@ TDataDifferences=class(TDataItem) // and return the differences both in structure and data in the Diff parameter. TDataCompare=record private - class function Same(const Before,After:TDataItem; out Diff:TItemDifference):Boolean; overload; static; - class function Same(const Before,After:TDataItems; out Diff:TItemDifferences):Boolean; overload; static; + class function Same(const Before,After:TDataItem; var Diff:TItemDifference):Boolean; overload; static; + class function Same(const Before,After:TDataItems; var Diff:TItemDifferences):Boolean; overload; static; - class function Same(const Before,After:TDataItem; out Diff:TBaseDifferences):Boolean; overload; static; + class function Same(const Before,After:TDataItem; var Diff:TBaseDifferences):Boolean; overload; static; // class function Same(const Before,After:TDataArray; const Diff:TDataDifferences):Boolean; overload; static; public class function Compare(const A:TDataItem; const ARow:TInteger; const B:TDataItem; const BRow:TInteger): Boolean; overload; static; class function Compare(const Before, After: TDataItem; const ARow:TInteger): Boolean; overload; static; class function Same(const Before,After:TDataItem):Boolean; overload; static; - class function Same(const Before,After:TDataItem; out Diff:TDifference):Boolean; overload; static; + class function Same(const Before,After:TDataItem; var Diff:TDifference):Boolean; overload; static; end; implementation diff --git a/src/delphi/BI.Dashboard.HTML.pas b/src/delphi/BI.Dashboard.HTML.pas index a39e427..3cda4ad 100644 --- a/src/delphi/BI.Dashboard.HTML.pas +++ b/src/delphi/BI.Dashboard.HTML.pas @@ -96,8 +96,8 @@ THTMLRender=class(TRender) procedure PrepareVariables(const AParams:TStrings); protected - procedure AddItemSeparator(const AIndex:Integer=-1; const AKind:String=''); override; - procedure AddListener(const AName:String; const ADataIndex:Integer); override; + procedure AddItemSeparator(const AIndex:Integer=-1; const AKind:TPanelKind=TPanelKind.Automatic); override; + procedure AddListener(const AName:String; const ASource:TObject); override; public const PureCSS=''; @@ -113,6 +113,8 @@ THTMLRender=class(TRender) Constructor Create; Destructor Destroy; override; + procedure Clear; override; + procedure Emit(const ADashboard:TDashboard; const AItem:Integer; const APosition:String); override; procedure Init(const ADashboard:TDashboard; const ALayout:String=''; const AParams:TStrings=nil); override; diff --git a/src/delphi/BI.Dashboard.Layouts.pas b/src/delphi/BI.Dashboard.Layouts.pas new file mode 100644 index 0000000..09985c1 --- /dev/null +++ b/src/delphi/BI.Dashboard.Layouts.pas @@ -0,0 +1,86 @@ +unit BI.Dashboard.Layouts; + +{$SCOPEDENUMS ON} + +interface + +uses + System.Classes, + BI.Data; + +type + TUnits=(Pixels,Percent); + + TBICoordinate=class(TPersistent) + private + FValue: Single; + FUnits: TUnits; + + procedure SetUnits(const Value: TUnits); + procedure SetValue(const AValue: Single); + public + procedure Assign(Source:TPersistent); override; + + procedure FromString(const S:String); + published + property Units:TUnits read FUnits write SetUnits default TUnits.Pixels; + property Value:Single read FValue write SetValue; + end; + + TLayouts=class; + + TLayoutStyle=(Automatic,Panels,Tabs,List,Combo); + + TLayoutItem=class(TCollectionItem) + private + FAlign : String; + FHeight : TBICoordinate; + FItems : TLayouts; // recursive + FName : String; + FNested : String; + FStyle : TLayoutStyle; + FWidth : TBICoordinate; + + function Get(const AIndex: Integer): TLayoutItem; + procedure Put(const AIndex: Integer; const Value: TLayoutItem); + + procedure SetItems(const Value:TLayouts); + procedure SetName(const Value:String); + public + Constructor Create(ACollection:TCollection); override; + Destructor Destroy; override; + + function Find(const AName:String):TLayoutItem; // Recursive + function IsHorizontal:Boolean; + function IsPanels:Boolean; + + property Item[const AIndex:Integer]:TLayoutItem read Get write Put; default; + published + property Align:String read FAlign write FAlign; + property Height:TBICoordinate read FHeight write FHeight; + property Items:TLayouts read FItems write SetItems; + property Name:String read FName write SetName; + property Nested:String read FNested write FNested; + property Style:TLayoutStyle read FStyle write FStyle default TLayoutStyle.Automatic; + property Width:TBICoordinate read FWidth write FWidth; + end; + + TLayouts=class(TOwnedCollection) + private + function Get(const AIndex: Integer): TLayoutItem; + procedure Put(const AIndex: Integer; const Value: TLayoutItem); + public + class var + Predefined : TLayouts; + + Destructor Destroy; override; + + procedure AddTo(const AItems: TStrings); + function Best(const ACount:Integer):String; + function Find(const AName:String):TLayoutItem; + function IndexOf(const AItem:TLayoutItem):Integer; + + property Item[const AIndex:Integer]:TLayoutItem read Get write Put; default; + end; + +implementation diff --git a/src/delphi/BI.Dashboard.Loader.pas b/src/delphi/BI.Dashboard.Loader.pas new file mode 100644 index 0000000..3bc7727 --- /dev/null +++ b/src/delphi/BI.Dashboard.Loader.pas @@ -0,0 +1,91 @@ +{*********************************************} +{ TeeBI Software Library } +{ TBITemplate Dashboard Loader methods } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.Dashboard.Loader; + +interface + +(* + The purpose of TTemplateLoader methods are to import a JSON file or string, + into a TBITemplate object. + + Example: + + TTemplateLoader.FromJSONFile('c:\mytemplate.json', BIVisual1.Template); + + Once the template has been loaded, we can edit properties, or display an + existing dashboard in the template: + + BIVisual1.Dashboard:=BIVisual1.Dashboards[0]; + + BIVisual1.Dashboard:='Dashboard 1'; + +*) + +uses + {$IFDEF FPC} + BI.FPC, Graphics, + {$ELSE} + System.UITypes, + {$ENDIF} + BI.Data, BI.Dashboard, BI.Dashboard.Layouts; + +type + TTemplateLoader=record + private + type + TBaseList=record + private + IList : TDataItem; + IOwnsList : Boolean; + + Index : Integer; + + function GetItem(const AName: String): String; inline; + procedure SetItem(const AName,AValue: String); + function GetBoolean(const AName:String; const ADefault:Boolean):Boolean; overload; inline; + function GetBoolean(const AList:TDataItem; const AName:String; const ADefault:Boolean):Boolean; overload; + function GetColor(const AName:String):TAlphaColor; overload; inline; + function GetColor(const AList:TDataItem; const AName:String):TAlphaColor; overload; + function GetString(const AList:TDataItem; const AName:String; const AIndex:Integer):String; overload; + public + function FindItem(const AName:String):TDataItem; + function FindSubItem(const AName,ASub:String; out AValue:String):Boolean; + + property Item[const AName:String]:String read GetItem write SetItem; default; + end; + + class function CreateDashboard(const ATemplate:TBITemplate; + const AList:TBaseList):TDashboard; static; + class function CreateData(const ATemplate:TBITemplate; + const AList: TBaseList):TVisualData; static; + class function CreateItem(const ATemplate:TBITemplate; + const ADashboard:TDashboard; + const AList:TBaseList):TDashboardItem; static; + + class function CreateLayout(const ATemplate: TBITemplate; + const ALayouts:TLayouts; + const AList: TBaseList):TLayoutItem; static; + + class function CreatePanel(const ATemplate:TBITemplate; + const AList:TBaseList):TBIPanel; static; + + class procedure LoadTemplate(const AData: TDataItem; const ATemplate:TBITemplate); static; + + public + class procedure FromJSON(const AJSON:String; const ATemplate:TBITemplate); static; + + class function FromJSONFile(const AFile:String):TBITemplate; overload; static; + class procedure FromJSONFile(const AFile:String; const ATemplate:TBITemplate); overload; static; + + class function ImportJSON(const AText:String):TDataItem; static; + + class procedure ImportLayouts(const ATemplate:TBITemplate; + const AData: TDataItem; + const ALayouts:TLayouts); static; + end; + +implementation diff --git a/src/delphi/BI.Dashboard.pas b/src/delphi/BI.Dashboard.pas index 8da7a21..33bdc07 100644 --- a/src/delphi/BI.Dashboard.pas +++ b/src/delphi/BI.Dashboard.pas @@ -18,7 +18,8 @@ interface System.Generics.Collections, {$ENDIF} - BI.Data, BI.Arrays, BI.UI, BI.Expression, BI.DataSource; + BI.Data, BI.Arrays, BI.UI, BI.Expression, BI.DataSource, + BI.Data.CollectionItem, BI.Dashboard.Layouts, BI.Query; type TChangeListener=class; @@ -27,26 +28,26 @@ TChangeListener=class; TChangeListener=class private - FIndex : Integer; FName : String; FOnChange : TChangeEvent; + FSource: TObject; public procedure Changed(const AValue:TExpression); - property Index:Integer read FIndex; property Name:String read FName; + property Source:TObject read FSource; end; TListeners={$IFDEF FPC}class(TFPGList){$ELSE}class(TList){$ENDIF} private - procedure Add(const AName:String; const AIndex:Integer; const AOnChange:TChangeEvent); + procedure Add(const AName:String; const ASource:TObject; const AOnChange:TChangeEvent); public Destructor Destroy; override; procedure Changed(const AName:String; const AValue:TExpression); end; - TVariable=record + TVariable=class private FValue : TExpression; @@ -61,7 +62,7 @@ TVariable=record TVariableArray=Array of TVariable; - TVariables={$IFDEF FPC}class(TFPGList){$ELSE}class(TList){$ENDIF} + TVariables={$IFDEF FPC}class(TFPGList){$ELSE}class(TObjectList){$ENDIF} protected IMain : TDataItem; @@ -70,187 +71,293 @@ TVariable=record {$ENDIF} public procedure Add(const AName:String; const AValue:TExpression); - procedure AddListener(const AName:String; const AIndex:Integer; const AOnChange:TChangeEvent); + procedure AddListener(const AName:String; const ASource:TObject; const AOnChange:TChangeEvent); procedure Change(const AName:String; const AValue:Boolean); overload; procedure Change(const AName:String; const AValue:TExpression); overload; function IndexOf(const AName:String):Integer; procedure TryAdd(const AName:String); end; - TBITemplate=class; + TVisualDataKind=(Data,Query,SingleRecord,Variable,FileURL,Custom); - TBaseItem=class(TComponent) + TVisualData=class(TDataCollectionItem) private - Index : Integer; - + FExpression : TExpression; + FName : String; IUsedVariables : TTextArray; - IVisual : TBITemplate; - IOwnsList : Boolean; - - procedure AddUsedVariable(const AName:String); - function GetItem(const AName: String): String; inline; - procedure SetItem(const AName,AValue: String); + procedure AddVariable(const AName:String); + function AsExpression:TExpression; + procedure Change(const Value:TExpression); + procedure Clear; + procedure SetName(const Value:String); function Variables:TVariables; protected - IList : TDataItem; + property Expression:TExpression read FExpression write FExpression; + published + property Name:String read FName write SetName; + end; - function GetBoolean(const AName:String; const ADefault:Boolean):Boolean; overload; inline; - function GetBoolean(const AList:TDataItem; const AName:String; const ADefault:Boolean):Boolean; overload; - function GetColor(const AName:String):TAlphaColor; overload; inline; - function GetColor(const AList:TDataItem; const AName:String):TAlphaColor; overload; - function GetString(const AList:TDataItem; const AName:String; const AIndex:Integer):String; overload; - function GetString(const AList:TDataItem; const AName:String):String; overload; inline; + TRender=class; - function ReplaceString(const S:String):String; + TVisualDataItems=class(TOwnedCollection) + private + procedure AddVariables(const ARender:TRender); -// function TryReplaceVariable(const S:String):String; + function Get(const Index: Integer): TVisualData; + procedure Put(const Index: Integer; const Value: TVisualData); + function UniqueName:String; public - Name : String; + function Add(const AData:TDataItem):TVisualData; + procedure Change(const AName:String; const AValue:TExpression); + function Find(const AName:String):TVisualData; + function IndexOf(const AName:String):Integer; overload; + function ValueOf(const AName:String):TExpression; - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem=nil; const AIndex:Integer=0); virtual; - Destructor Destroy; override; + property Item[const Index:Integer]:TVisualData read Get write Put; default; + end; + + TBITemplate=class; - function FindItem(const AName:String):TDataItem; - function FindSubItem(const AName,ASub:String; out AValue:String):Boolean; + TBaseItem=class(TCollectionItem) + private + FName : String; + IUsedVariables : TTextArray; + procedure AddUsedVariable(const AName:String); + procedure DoChanged; + function IsLoading:Boolean; + procedure SetName(const Value:String); + protected + function ReplaceString(const S:String):String; + function Template: TBITemplate; + function Variables:TVariables; + public function UsesVariable(const Sender:TChangeListener):Boolean; virtual; + published + property Name:String read FName write SetName; + end; + + TBIFont=class(TPersistent) + private + FBold : Boolean; + FColor : TAlphaColor; + FFamily : String; + FItalic : Boolean; + FSize : Single; - property Item[const AName:String]:String read GetItem write SetItem; default; + procedure SetColor(const Value: TAlphaColor); + published + property Bold:Boolean read FBold write FBold default False; + property Color:TAlphaColor read FColor write SetColor default TAlphaColors.Null; + property Family:String read FFamily write FFamily; + property Italic:Boolean read FItalic write FItalic default False; + property Size:Single read FSize write FSize; end; - TBIFont=class(TBaseItem) - public - Color : TAlphaColor; + TPanelKind=(Automatic,Grid,List,Text,CheckList,Combo,Buttons,Image,Slider, + Check,Navigator,Tree,Radio,Chart); - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem; const AIndex:Integer=0); override; + TPanelKindHelper=record helper for TPanelKind + public + class function From(const S:String):TPanelKind; static; + function ToString:String; end; - TBIPanel=class(TBaseItem) + TCustomBIPanel=class(TBaseItem) private - FData : TDataItem; + FBack : TAlphaColor; + FDisplay : String; + FFont : TBIFont; + FKey : String; + FKind : TPanelKind; + FSource, + FTarget, + FTitle, + FURL : String; + FHeight, - FWidth : String; + FWidth : TBICoordinate; + + IDataLoad : String; + IData : TVisualData; ISelect : TDataItem; - function GetData: TDataItem; - procedure SetData(const Value: TDataItem); - function TrySelect(const AData:TDataItem):TDataItem; - protected - IData : Integer; + function GetData:String; + procedure LinkData(const AData: String); + procedure SetData(const Value: String); + procedure SetVisualData(const Value: TVisualData); + procedure SetBack(const Value: TAlphaColor); + + procedure SetFont(const Value: TBIFont); + procedure SetHeight(const Value: TBICoordinate); + procedure SetKind(const Value: TPanelKind); + procedure SetTarget(const Value: String); + procedure SetWidth(const Value: TBICoordinate); public - Back : TAlphaColor; - Kind : String; - Target : String; - Font : TBIFont; - - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem=nil; const AIndex:Integer=0); override; + Constructor Create(Collection:TCollection); override; Destructor Destroy; override; function UsesVariable(const Sender:TChangeListener):Boolean; override; + property VisualData:TVisualData read IData write SetVisualData; + + { To be published } + property Back:TAlphaColor read FBack write SetBack default TAlphaColors.Null; + property Data:String read GetData write SetData; + property Display:String read FDisplay write FDisplay; + property Font:TBIFont read FFont write SetFont; + property Height:TBICoordinate read FHeight write SetHeight; + property Key:String read FKey write FKey; + property Kind:TPanelKind read FKind write SetKind default TPanelKind.Automatic; + property Source:String read FSource write FSource; + property Target:String read FTarget write SetTarget; + property Title:String read FTitle write FTitle; + property URL:String read FURL write FURL; + property Width:TBICoordinate read FWidth write SetWidth; + end; + + TBIPanel=class(TCustomBIPanel) published - property Data:TDataItem read GetData write SetData; - property Height : String read FHeight write FHeight; - property Width : String read FWidth write FWidth; + property Back; + property Data; + property Font; + property Height; + property Kind; + property Source; + property Target; + property URL; + property Width; end; - TDashboardItem=class(TBaseItem) + TDashboard=class; + + TDashboardItem=class(TCustomBIPanel) private - FHeight, - FPosition, - FWidth : String; + FCSSClass, + FSelected, + FText : String; + + FColorize : Boolean; + FHorizontal : Boolean; + FNavigator : Boolean; - FPanel : TBIPanel; + FMin, + FMax, + FPadding : Single; + FPosition : String; + FPanel : TCustomBIPanel; + + FVisible: Boolean; + + // DashboardTree + FMaster, + FDetail : TDataItem; + + IPanelLoad, IPosition : String; + procedure ClearVariables; function DoGetSelected(const AData:TDataItem; const AIndex:Integer): String; + function GetDashboard: TDashboard; function GetDisplayData(const AData:TDataItem):TDataItem; function GetKeyData(const AData:TDataItem):TDataItem; - procedure SetPanel(const APanel:TBIPanel); + function GetPanel:String; + function GetText:String; + procedure LinkPanel(const APanel: String); + procedure Loaded; + procedure SetPanel(const APanel:String); + procedure SetVisible(const Value: Boolean); protected - Dashboard : TBIPanel; - - function TryGetSub(const AName,ASubName:String; out AValue:String):Boolean; + Format : String; + Minify : Boolean; // HTML JS public - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem=nil; const AIndex:Integer=0); override; + Constructor Create(Collection:TCollection); override; - function CalcKind:String; + function CalcDisplay:String; + function CalcKind:TPanelKind; function CountOfData:TInteger; - function GetData(const AName:String):String; function GetSelected(const AIndex:Integer):String; function GetSelectedDisplay(const AIndex:Integer): String; function SelectedIndex:Integer; - function Text:String; function UsesVariable(const Sender:TChangeListener):Boolean; override; + + property Dashboard:TDashboard read GetDashboard; + property Detail:TDataItem read FDetail; + property Master:TDataItem read FMaster; + property PanelItem:TCustomBIPanel read FPanel write FPanel; + property RealPosition:String read IPosition; published - property Height : String read FHeight write FHeight; - property Panel : TBIPanel read FPanel write SetPanel; + property CSSClass:String read FCSSClass write FCSSClass; + property Colorize:Boolean read FColorize write FColorize default False; + property Height; + property Horizontal:Boolean read FHorizontal write FHorizontal default False; + property Kind; + property Max:Single read FMax write FMax; + property Min:Single read FMin write FMin; + property Navigator:Boolean read FNavigator write FNavigator default False; + property Padding:Single read FPadding write FPadding; + property Panel:String read GetPanel write SetPanel; property Position:String read FPosition write FPosition; - property Width : String read FWidth write FWidth; - end; - - TDashboardItems={$IFDEF FPC}class(TFPGList){$ELSE}class(TList){$ENDIF} - public - function Add(const APanel:TBIPanel):TDashboardItem; overload; + property Selected:String read FSelected write FSelected; + property Target; + property Text:String read GetText write FText; + property Title; + property URL; + property Visible:Boolean read FVisible write SetVisible default True; + property Width; end; - TLayouts=class; - - TLayoutItem=class(TBaseItem) + TDashboardItems=class(TOwnedCollection) private + procedure ClearPositions; + function Get(const Index: Integer): TDashboardItem; + procedure Loaded; + procedure Put(const Index: Integer; const Value: TDashboardItem); + function UniqueName:String; + function VisibleCount:Integer; public - Align : String; - Height : String; - Items : TLayouts; - Nested : String; - Style : String; - Width : String; - - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem=nil; const AIndex:Integer=0); override; - Destructor Destroy; override; - - function Find(const AName:String):TLayoutItem; // Recursive - function IsHorizontal:Boolean; - end; - - TLayouts={$IFDEF FPC}class(TFPGList){$ELSE}class(TList){$ENDIF} - private - class var - FPredefined : TLayouts; - - procedure ImportFrom(const AVisual:TBITemplate; const AData:TDataItem); - public - Destructor Destroy; override; - - procedure AddTo(const AItems: TStrings); - function Find(const AName:String):TLayoutItem; + function Add(const APanel:TBIPanel):TDashboardItem; overload; + function IndexOf(const AName:String):Integer; - class function Predefined:TLayouts; static; + property Item[const Index:Integer]:TDashboardItem read Get write Put; default; end; - TDashboard=class(TBIPanel) + TDashboard=class(TCustomBIPanel) private FItems : TDashboardItems; FLayout : String; + FPadding : Single; FSplitters : Boolean; FTitles : Boolean; - function GetItems:TDashboardItems; + function Get(const AIndex: Integer): TDashboardItem; function IsFreePosition(const AName:String):Boolean; + procedure Loaded; + procedure Put(const AIndex: Integer; const Value: TDashboardItem); + procedure SetLayout(const Value: String); + procedure SetItems(const Value: TDashboardItems); + protected + FLayoutItem : TLayoutItem; public - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem=nil; const AIndex:Integer=0); override; + Constructor Create(ACollection:TCollection); override; Destructor Destroy; override; function Find(const APanel:TBIPanel):TDashboardItem; function IndexOfPanel(const AName:String):Integer; - property Items:TDashboardItems read GetItems; + property Item[const AIndex:Integer]:TDashboardItem read Get write Put; default; + property LayoutItem:TLayoutItem read FLayoutItem; published - property Layout : String read FLayout write FLayout; - property Splitters : Boolean read FSplitters write FSplitters default True; - property Titles : Boolean read FTitles write FTitles default False; + property Back; + property Height; + property Items:TDashboardItems read FItems write SetItems; + property Layout:String read FLayout write SetLayout; + property Padding:Single read FPadding write FPadding; + property Splitters:Boolean read FSplitters write FSplitters default True; + property Titles:Boolean read FTitles write FTitles default True; + property Width; end; TRender=class @@ -267,15 +374,15 @@ TRender=class class procedure AddItems(const AItems: TStrings; const AData:TDataItem; const ADisplay:String=''); static; - procedure AddItemSeparator(const AIndex:Integer=-1; const AKind:String=''); virtual; - procedure AddListener(const AName:String; const ADataIndex:Integer); virtual; abstract; - function BestLayout(const ADashboard:TDashboard):String; + procedure AddItemSeparator(const AIndex:Integer=-1; const AKind:TPanelKind=TPanelKind.Automatic); virtual; + procedure AddListener(const AName:String; const ASource:TObject); virtual; abstract; procedure ChangeSelected(const AItem:TDashboardItem; const AIndex:Integer); class function DataAsString(const AData:TDataItem):String; static; function FindRootLayout(const AName:String):TLayoutItem; function GetColorizers(const AItem:TDashboardItem):TDataColorizers; function TopRender:TRender; public + procedure Clear; virtual; abstract; procedure Emit(const ADashboard:TDashboard; const AItem:Integer; const APosition:String); overload; virtual; class function GetDisplayData(const AData:TDataItem; const AName:String=''):TDataItem; static; @@ -286,105 +393,81 @@ TRender=class TRenderClass=class of TRender; - TPanels={$IFDEF FPC}class(TFPGList){$ELSE}class(TList){$ENDIF} - public - function IndexOf(const AName:String):Integer; - end; - - TDashboards={$IFDEF FPC}class(TFPGList){$ELSE}class(TList){$ENDIF} - public - function IndexOf(const AName:String):Integer; - end; - - TVisualDataKind=(Data,Query,SingleRecord,Variable,FileURL,Custom); - - TVisualData=class(TBaseItem) + TPanels=class(TOwnedCollection) private - FKind : TVisualDataKind; - FStore : String; - - IDataOrigin: String; - IData : TDataItem; - IExpression : TExpression; - IMain : TDataItem; - IValue : TExpression; - - DataIndex : Integer; - - procedure Change(const AValue:TExpression); - function ExpressionValue:TExpression; - function SingleRecordFrom(const AData: TDataItem):TDataItem; + function Get(const Index: Integer): TBIPanel; + procedure Loaded; + procedure Put(const Index: Integer; const Value: TBIPanel); + function UniqueName:String; public - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem; const AIndex:Integer=0); override; - Destructor Destroy; override; + function Add(const AData:TVisualData):TBIPanel; + function Find(const AName:String):TBIPanel; + function IndexOf(const AName:String):Integer; - procedure Clear; - function Data:TDataItem; - procedure Reset; - function Value:TExpression; - published - property Kind : TVisualDataKind read FKind write FKind; - property Store : String read FStore write FStore; + property Item[const Index:Integer]:TBIPanel read Get write Put; default; end; - TVisualDataArray=Array of TVisualData; - - TVisualDataArrayHelper=record helper for TVisualDataArray + TDashboards=class(TOwnedCollection) private - procedure AddVariables(const ARender:TRender); + function Get(const Index: Integer): TDashboard; + procedure Loaded; + procedure Put(const Index: Integer; const Value: TDashboard); + function UniqueName:String; public - procedure Change(const AName:String; const AValue:TExpression); - procedure Clear; - function Count:Integer; inline; + function Add:TDashboard; + function Find(const AName:String):TDashboard; function IndexOf(const AName:String):Integer; - function ValueOf(const AName:String):TExpression; + + property Item[const Index:Integer]:TDashboard read Get write Put; default; end; - TBITemplate=class(TBaseItem) + TBITemplate=class(TComponent) private - IRender : TRender; + FDashboards : TDashboards; + FData : TVisualDataItems; + FLayouts : TLayouts; + FPanels : TPanels; + IList : TDataItem; IMainData : TDataItem; + IRender : TRender; - function CreateDashboard(const AList:TDataItem; - const AIndex:Integer):TDashboard; - function CreatePanel(const AList:TDataItem; - const AIndex:Integer):TBIPanel; - - function ParseSQL(const AMain:TDataItem; const SQL:String; const AIndex:Integer):TDataItem; + procedure DataResolver(const AName:String; out AData:TDataItem); + function ProviderFromSQL(const ADest:TVisualData; const SQL: String): TDataProvider; + procedure SetDashboards(const Value: TDashboards); + procedure SetData(const Value: TVisualDataItems); + procedure SetLayouts(const Value: TLayouts); + procedure SetPanels(const Value: TPanels); protected - Owner : TObject; - function FindData(const AStore,AName:String):TDataItem; function GetItem(const AName:String):TDataItem; + property List:TDataItem read IList write IList; + procedure Loaded; override; + function NewOwner:TComponent; function PanelData(const APanel:TBIPanel):TDataItem; public - Dashboards : TDashboards; - Data : TVisualDataArray; - Layouts : TLayouts; - Panels : TPanels; - class var Root : String; - Constructor CreateData(const AVisual:TBITemplate; const AList:TDataItem; const AIndex:Integer=0); override; + Constructor Create(Owner:TComponent); override; Destructor Destroy; override; + procedure Clear; function FindLayout(const ALayout:String):TLayoutItem; - class function FromData(const AData:TDataItem):TBITemplate; static; - class function FromJSON(const AJSON:String):TBITemplate; static; - class function FromJSONFile(const AJSONFile:String):TBITemplate; static; - procedure Generate(const ARender:TRender; const ADashboard:TDashboard; const ALayout:String=''; const AParams:String=''); class function GetMasterDetail(const AData:TDataItem; const AIndex:TInteger):TCursorIndex; + function NewQuery(const ADest:TVisualData; const SQL:String):TBIQuery; - class function ImportJSON(const AText:String):TDataItem; - - property List:TDataItem read IList; // deprecated ? + property MainData:TDataItem read IMainData write IMainData; + published + property Dashboards:TDashboards read FDashboards write SetDashboards; + property Data:TVisualDataItems read FData write SetData; + property Layouts:TLayouts read FLayouts write SetLayouts; + property Panels:TPanels read FPanels write SetPanels; end; implementation diff --git a/src/delphi/BI.Data.CSV.pas b/src/delphi/BI.Data.CSV.pas index 3434bd3..303604c 100644 --- a/src/delphi/BI.Data.CSV.pas +++ b/src/delphi/BI.Data.CSV.pas @@ -47,10 +47,10 @@ TBICSV=class(TBITextSource) t1 : TStopwatch; - class function BISplitString(const AString:String; const ADelimiter,AQuote:Char):TStringDynArray; + class function BISplitString(const AString:String; const ADelimiter,AQuote:Char):TStringArray; function Dequoted(const S:String):String; - procedure GuessDataKinds(const AData:TDataItem; const Values:TStringDynArray {TArray}); - function GuessDelimiter(const AText:String):TStringDynArray; + procedure GuessDataKinds(const AData:TDataItem; const Values:TStringArray); + function GuessDelimiter(const AText:String):TStringArray; function GuessHeaders(const AString:String):Boolean; function FinishRowByRow(const ACount:TInteger):TDataArray; diff --git a/src/delphi/BI.Data.DB.BDE.pas b/src/delphi/BI.Data.DB.BDE.pas index 6e3a5cb..6ca0853 100644 --- a/src/delphi/BI.Data.DB.BDE.pas +++ b/src/delphi/BI.Data.DB.BDE.pas @@ -28,7 +28,8 @@ TDBBDEEngine=class(TBIDBEngine) class function DriverToName(const ADriver:String):String; override; class function GetConnectionName(const AConnection:TCustomConnection):String; override; class function GetDriver(const AIndex:Integer):String; override; - class function GetItemNames(const AConnection:TCustomConnection; const IncludeSystem:Boolean):TStrings; override; + class function GetItemNames(const AConnection:TCustomConnection; + const IncludeSystem,IncludeViews:Boolean):TStrings; override; class function GetKeyFieldNames(const AConnection:TCustomConnection; const ATable:String):TStrings; override; class function GetSchemas(const AConnection:TCustomConnection):TStrings; class function GetTable(const AConnection:TCustomConnection; const AName:String):TDataSet; override; diff --git a/src/delphi/BI.Data.DB.FireDAC.AllDrivers.pas b/src/delphi/BI.Data.DB.FireDAC.AllDrivers.pas index d9a70d4..424a36a 100644 --- a/src/delphi/BI.Data.DB.FireDAC.AllDrivers.pas +++ b/src/delphi/BI.Data.DB.FireDAC.AllDrivers.pas @@ -54,7 +54,8 @@ interface {$ENDIF} uses - BI.Data.DB, + System.Classes, + BI.Data, BI.Data.DB, {$IFDEF HASFIREDAC} FireDAC.Stan.Intf, FireDAC.Stan.Option, @@ -117,6 +118,8 @@ interface {$IFDEF HASFIREDAC_SQLite} // SQLite FireDAC.Phys.SQLite, + FireDAC.Phys.SQLiteVDataSet, + {$IF CompilerVersion>27} FireDAC.Phys.SQLiteDef, {$ENDIF} @@ -148,8 +151,17 @@ interface type TBIDBFireDACTester=class(TBIDBTester) public - class function Test(const Driver,Database,Server,Port,User,Password:String; - const Prompt:Boolean):Boolean; override; + class procedure Test(const Driver,Database,Server,Port,User,Password:String; + const Prompt:Boolean); override; + end; + + {$IFDEF HASFIREDAC_SQLite} // SQLite + TBILocalSQL=record + public + class procedure Add(const AOwner:TComponent; const AData:TDataItem; const ALocal:TFDLocalSQL); static; + class function From(const ALocal:TFDLocalSQL):TDataItem; overload; static; + class function From(const AOwner:TComponent; const AData:TDataItem):TFDLocalSQL; overload; static; end; + {$ENDIF} implementation diff --git a/src/delphi/BI.Data.DB.FireDAC.pas b/src/delphi/BI.Data.DB.FireDAC.pas index 6757564..c4685ef 100644 --- a/src/delphi/BI.Data.DB.FireDAC.pas +++ b/src/delphi/BI.Data.DB.FireDAC.pas @@ -26,7 +26,8 @@ TDBFireDACEngine=class(TBIDBEngine) class function GetKeyFieldNames(const AConnection:TCustomConnection; const ATable:String):TStrings; override; class function GetSchemas(const AConnection:TCustomConnection):TStrings; class function GetTable(const AConnection:TCustomConnection; const AName:String):TDataSet; override; - class function GetItemNames(const AConnection:TCustomConnection; const IncludeSystem:Boolean):TStrings; override; + class function GetItemNames(const AConnection:TCustomConnection; + const IncludeSystem,IncludeViews:Boolean):TStrings; override; class procedure GuessForeignKeys(const AName:String; const Table:TDataSet; const AData:TDataItem; const Source:TBISource); override; class function ImportFile(const Source:TBIDB; const AFileName:String):TDataArray; override; class procedure StartParallel; override; diff --git a/src/delphi/BI.Data.DB.SqlExpr.pas b/src/delphi/BI.Data.DB.SqlExpr.pas index c45fd40..815aa33 100644 --- a/src/delphi/BI.Data.DB.SqlExpr.pas +++ b/src/delphi/BI.Data.DB.SqlExpr.pas @@ -14,6 +14,10 @@ interface type TDBSqlExprEngine=class(TBIDBEngine) + private + class function DoCreateConnection(const ADriver,AServer,APort, + ADatabase,AUser,APassword:String; + const LoginPrompt:Boolean):TCustomConnection; public const DBDriverNames:Array[0..8] of String=('SQLite','MySQL','Oracle','Microsoft SQL Server', @@ -32,7 +36,8 @@ TDBSqlExprEngine=class(TBIDBEngine) class function GetKeyFieldNames(const AConnection:TCustomConnection; const ATable:String):TStrings; override; class function GetSchemas(const AConnection:TCustomConnection):TStrings; class function GetTable(const AConnection:TCustomConnection; const AName:String):TDataSet; override; - class function GetItemNames(const AConnection:TCustomConnection; const IncludeSystem:Boolean):TStrings; override; + class function GetItemNames(const AConnection:TCustomConnection; + const IncludeSystem,IncludeViews:Boolean):TStrings; override; class procedure GuessForeignKeys(const AName:String; const Table:TDataSet; const AData:TDataItem; const Source:TBISource); override; class function ImportFile(const Source:TBIDB; const AFileName:String):TDataArray; override; class function Supports(const Extension:String):Boolean; override; diff --git a/src/delphi/BI.Data.DB.pas b/src/delphi/BI.Data.DB.pas index 5dfc199..0d10319 100644 --- a/src/delphi/BI.Data.DB.pas +++ b/src/delphi/BI.Data.DB.pas @@ -17,15 +17,15 @@ TBIDB=class; TBIDBTester=class abstract public - class function Test(const Driver,Database,Server,Port,User,Password:String; - const Prompt:Boolean):Boolean; virtual; abstract; + class procedure Test(const Driver,Database,Server,Port,User,Password:String; + const Prompt:Boolean); virtual; abstract; end; TBIDBTesterClass=class of TBIDBTester; TBIDBEngine=class abstract public - class procedure AddFields(const Fields:TFieldDefs; const Data:TDataItem); + class procedure AddFields(const Fields:TFieldDefs; const AItems:TDataArray); class function CloneConnection(const AConn:TCustomConnection): TCustomConnection; virtual; abstract; class function CreateConnection(const Definition:TDataDefinition):TCustomConnection; virtual; abstract; class function CreateDataSet(const AOwner:TComponent; const AData:TDataItem):TDataSet; virtual; abstract; @@ -36,7 +36,8 @@ TBIDBEngine=class abstract class function GetDriver(const AIndex:Integer):String; virtual; abstract; class function GetKeyFieldNames(const AConnection:TCustomConnection; const ATable:String):TStrings; virtual; abstract; class function GetTable(const AConnection:TCustomConnection; const AName:String):TDataSet; virtual; abstract; - class function GetItemNames(const AConnection:TCustomConnection; const IncludeSystem:Boolean):TStrings; virtual; abstract; + class function GetItemNames(const AConnection:TCustomConnection; + const IncludeSystem,IncludeViews:Boolean):TStrings; virtual; abstract; class procedure GuessForeignKeys(const AName:String; const Table:TDataSet; const AData:TDataItem; const Source:TBISource); virtual; abstract; class function ImportFile(const Source:TBIDB; const AFileName:String):TDataArray; virtual; abstract; @@ -53,7 +54,8 @@ TBIDB=class(TBIDatasetSource) function Import(const Connection:TCustomConnection; const AName:String):TDataItem; overload; class function GetEngine: TBIDBEngine; static; - function GetItems(const Connection:TCustomConnection):TStrings; + function GetItems(const Connection:TCustomConnection):TStrings; overload; + class function GetItems(const ADefinition:TDataDefinition):TStrings; overload; class procedure SetEngine(const Value: TBIDBEngine); static; protected function DoImportFile(const FileName:String):TDataArray; override; @@ -70,8 +72,7 @@ TBIDB=class(TBIDatasetSource) TBIDBExport=class public - class function ToMemTable(const AOwner:TComponent; const Data:TDataItem):TDataSet; static; -// class function ToMemTable(const AOwner:TComponent; const Cursor:TDataCursor):TDataSet; overload; static; + class function From(const AOwner:TComponent; const Data:TDataItem):TDataSet; static; end; implementation diff --git a/src/delphi/BI.Data.Dataset.pas b/src/delphi/BI.Data.Dataset.pas index 03bbe9d..84ae27d 100644 --- a/src/delphi/BI.Data.Dataset.pas +++ b/src/delphi/BI.Data.Dataset.pas @@ -17,6 +17,7 @@ TBIDataSetSource=class(TBIFileSource) procedure AddField(const AData:TDataItem; const AField:TField); procedure AddFields(const AData:TDataItem; const AFields:TFields); function DataFromADT(const AField:TField):TDataItem; + procedure DoLoadData(const ADataSet:TDataSet; const AData:TDataItem); procedure GuessFields(const ADataSet:TDataSet; const AData:TDataItem); procedure LoadData(const ADataSet:TDataSet; const AData:TDataItem); public diff --git a/src/delphi/BI.Data.Expressions.pas b/src/delphi/BI.Data.Expressions.pas index fc11afe..3f158c7 100644 --- a/src/delphi/BI.Data.Expressions.pas +++ b/src/delphi/BI.Data.Expressions.pas @@ -26,7 +26,6 @@ THop=class Items : TDataArray; // Multiple function CreateInvertedIndex(const AIndex:TNativeIntArray):TNativeIntArray; - //function Find(const AIndex:TInteger):TInteger; procedure Prepare; public Constructor Create(const AData:TDataItem); overload; @@ -38,6 +37,8 @@ THop=class THopArray=Array of THop; THopArrayHelper=record helper for THopArray + private + procedure FreeAll; public procedure Add(const Hop:THop); procedure AddTop(const Hop:THop); @@ -45,7 +46,7 @@ THopArrayHelper=record helper for THopArray end; function InternalFind(const Start,Dest:TDataItem; var Visited:TDataArray):THops.THopArray; - + procedure Invalidate(const AIndex:TInteger); public var Items : THopArray; @@ -224,6 +225,19 @@ TDataExpression=class private class var FResolver : TResolver; + + {$IFDEF FPC} + type + TDataExpressionClass=class of TDataExpression; + + class var + IResolveError : TErrorProc; + IData : TDataItem; + IClass : TDataExpressionClass; + + function ResolveFunction(const S:String; IsFunction:Boolean):TExpression; + class function CallError(const Sender:TObject; const Text:String):Boolean; + {$ENDIF} protected class function Resolve(const AData:TDataItem; const AText:String; const Error:TErrorProc):TExpression; virtual; diff --git a/src/delphi/BI.Data.Html.pas b/src/delphi/BI.Data.Html.pas index e097271..a7d3e35 100644 --- a/src/delphi/BI.Data.Html.pas +++ b/src/delphi/BI.Data.Html.pas @@ -11,7 +11,7 @@ interface uses System.Classes, System.Types, {$IFDEF FPC} - Graphics, + BI.FPC, Graphics, {$ELSE} System.UITypes, {$ENDIF} @@ -60,7 +60,7 @@ TBIHtmlHelper=class TableClass:String; class function Color(const AColor:TColor):String; static; - class function Combo(const AName:String; const Texts,Values:TStringDynArray): String; static; + class function Combo(const AName:String; const Texts,Values:TStringArray): String; static; class function Escape(const S:String):String; static; class function FinishForm(const AName:String):String; static; class function Hidden(const AName:String; const AValue:Integer):String; overload; static; diff --git a/src/delphi/BI.Data.RTTI.pas b/src/delphi/BI.Data.RTTI.pas index a2c9eee..759f468 100644 --- a/src/delphi/BI.Data.RTTI.pas +++ b/src/delphi/BI.Data.RTTI.pas @@ -24,7 +24,7 @@ interface uses System.Classes, System.TypInfo, System.Rtti, System.Generics.Collections, - BI.Arrays, BI.Data, BI.Persist; + BI.Arrays, BI.Data, BI.Persist, BI.Expression; type TVisibility=set of TMemberVisibility; @@ -96,4 +96,29 @@ TTypeProvider=class(TRTTIProvider) property Items[const Index:TInteger]:T read Get write Put; default; end; + TObjectExpression=class(TExpression) + private + FField: String; + FInstance: TObject; + + ICached : Boolean; + IValue : TData; + + function Calculate: TValue; + class function GetValue(const AInstance:TObject; const AField:String): TValue; static; + procedure SetField(const Value: String); + procedure SetInstance(const Value: TObject); + public + class function From(const AObject:TObject; const AField:String):TObjectExpression; + + procedure Assign(const Source:TExpression); override; + class function Parse(const AContext:TObject; const S:String):TObjectExpression; + procedure Refresh; + function ToString:String; override; + function Value:TData; override; + + property Instance:TObject read FInstance write SetInstance; + property FieldName:String read FField write SetField; + end; + implementation diff --git a/src/delphi/BI.Data.SQL.pas b/src/delphi/BI.Data.SQL.pas index 81db2b6..7ef3a86 100644 --- a/src/delphi/BI.Data.SQL.pas +++ b/src/delphi/BI.Data.SQL.pas @@ -15,8 +15,12 @@ interface type ESQLParser=class(EBIException); - TGetDataProc={$IFNDEF FPC}reference to{$ENDIF} - procedure(const AName:String; out AData:TDataItem); + TGetDataProc= + {$IFDEF FPC} + procedure(const AName:String; out AData:TDataItem) of object; + {$ELSE} + reference to procedure(const AName:String; out AData:TDataItem); + {$ENDIF} // Converts an SQL string to its equivalent query (TDataSelect) or // summary (TSummary) object instance @@ -30,20 +34,25 @@ TSQLParser=class ILength, IPos : Integer; + function CallDoError(const Sender:TObject; const Error:String):Boolean; class function DataOf(const AParent:TDataItem; const AData:String; out AExp:TExpression):TDataItem; static; procedure DoError(const AError:String); function EndOfText:Boolean; function GetExpression: String; function GetExpressions:TTextArray; + class function IgnoreError(const Sender:TObject; const Error:String):Boolean; function NextIdent:String; function Optional(const AText:String):Boolean; + function ParseWhere(const AData:TDataItem; const AWhere:String):TBaseLogicalExpression; + procedure SkipDelimiters; protected class function DataFromString(const AData:TDataItem; const S:String):TDataItem; static; public Constructor Create(const AData:TDataItem; const AText:String); function Calculate(const ErrorProc:TBIErrorProc=nil):TDataItem; + class function DataFrom(const AProvider:TDataProvider): TDataItem; static; class function FindAggregate(var S:String; out Agg:TAggregate):Boolean; static; class function FindGroupByPart(var S:String; out APart:TDateTimePart):Boolean; static; @@ -90,6 +99,11 @@ TBISQL=record const GetData:TGetDataProc=nil; const ErrorProc:TBIErrorProc=nil):TDataItem; overload; static; + // Parse SQL syntax and return provider + class function ProviderFrom(const AData:TDataItem; const SQL:String; + const GetData:TGetDataProc=nil; + const ErrorProc:TBIErrorProc=nil):TDataProvider; overload; static; + // Return SQL from AData Provider: class function From(const AData:TDataItem):String; overload; static; end; diff --git a/src/delphi/BI.Data.Search.pas b/src/delphi/BI.Data.Search.pas index 1ecdb1c..d33f734 100644 --- a/src/delphi/BI.Data.Search.pas +++ b/src/delphi/BI.Data.Search.pas @@ -14,13 +14,16 @@ interface {$ENDIF} {$ENDIF} - uses System.Classes, + {$IFDEF FPC} + // MTProcs, <-- DoParallel + {$ELSE} {$IFDEF THREADING} System.Threading, {$ENDIF} + {$ENDIF} BI.Data, BI.Arrays, BI.DataSource; @@ -28,8 +31,8 @@ interface // content as text of one field or all fields. type - TSearchFinished={$IFNDEF FPC}reference to{$ENDIF} procedure(const AIndex:TCursorIndex); - TSearchProgress={$IFNDEF FPC}reference to{$ENDIF} procedure(var Stop:Boolean); + TSearchFinished=procedure(const AIndex:TCursorIndex) of object; + TSearchProgress=procedure(var Stop:Boolean) of object; TDataSearchPart=(Anywhere, AtStart, AtEnd, Exact); @@ -55,8 +58,18 @@ TDataSearch=record Task : ITask; {$ENDIF} + function AsDateTime(const AItem:TDataItem; const AIndex:TInteger):String; + + function AsFloat(const Value:Single):String; overload; + function AsFloat(const Value:Double):String; overload; + + {$IFNDEF CPUX64} + function AsFloat(const Value:Extended):String; overload; + {$ENDIF} + function AsString(const AItem:TDataItem; const AIndex:TInteger):String; function DoFind(const AText:String):TCursorIndex; + procedure Finish(const AIndex:TCursorIndex); public CaseSensitive : Boolean; // Default: False (ignore upper or lower case) diff --git a/src/delphi/BI.Data.SingleRecord.pas b/src/delphi/BI.Data.SingleRecord.pas new file mode 100644 index 0000000..c5cd179 --- /dev/null +++ b/src/delphi/BI.Data.SingleRecord.pas @@ -0,0 +1,37 @@ +{*********************************************} +{ TeeBI Software Library } +{ Single Record from a TDataItem row } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.Data.SingleRecord; + +interface + +uses + System.Classes, BI.Arrays, BI.Data, BI.Persist; + +type + // Returns a TDataItem that is a record-view of another AData item, + // for the specified ARow record + TSingleRecord=class(TDataProvider) + private + FRow : TInteger; + FData: TDataItem; + + procedure SetRow(const Value:TInteger); + procedure SetData(const Value: TDataItem); + protected + procedure Changed; override; + procedure Load(const AData:TDataItem; const Children:Boolean); override; + procedure Notify(const AEvent:TBIEvent); + public + Constructor Create(AOwner:TComponent); override; + + class function From(const AData:TDataItem; const ARow:TInteger):TDataItem; static; + published + property Data:TDataItem read FData write SetData; + property Row:TInteger read FRow write SetRow; + end; + +implementation diff --git a/src/delphi/BI.Data.SqlDB.pas b/src/delphi/BI.Data.SqlDB.pas index 653d50b..8d3db3b 100644 --- a/src/delphi/BI.Data.SqlDB.pas +++ b/src/delphi/BI.Data.SqlDB.pas @@ -35,7 +35,8 @@ TDBSqlDBEngine=class(TBIDBEngine) class function GetKeyFieldNames(const AConnection:TCustomConnection; const ATable:String):TStrings; override; class function GetSchemas(const AConnection:TCustomConnection):TStrings; class function GetTable(const AConnection:TCustomConnection; const AName:String):TDataSet; override; - class function GetItemNames(const AConnection:TCustomConnection; const IncludeSystem:Boolean):TStrings; override; + class function GetItemNames(const AConnection:TCustomConnection; + const IncludeSystem,IncludeViews:Boolean):TStrings; override; class procedure GuessForeignKeys(const AName:String; const Table:TDataSet; const AData:TDataItem; const Source:TBISource); override; class function ImportFile(const Source:TBIDB; const AFileName:String):TDataArray; override; class function Supports(const Extension:String):Boolean; override; diff --git a/src/delphi/BI.Data.Workflow.pas b/src/delphi/BI.Data.Workflow.pas index 2a5061d..a17664e 100644 --- a/src/delphi/BI.Data.Workflow.pas +++ b/src/delphi/BI.Data.Workflow.pas @@ -33,8 +33,9 @@ interface } uses - System.Classes, BI.Data, BI.Persist, BI.Query, - BI.DataSource, BI.Summary, BI.Store.Component, BI.Data.CollectionItem; + System.Classes, BI.Data, BI.Persist, BI.Query, BI.Arrays, + BI.DataSource, BI.Summary, //BI.Store.Component, + BI.Data.CollectionItem; type TWorkflowAction=class(TBaseDataImporter) @@ -147,6 +148,8 @@ TRenameItem=class(TItemAction) end; TDataTranspose=class(TWorkflowAction) + private + procedure TransposeRow(const ADest:TDataItem; const ARow:TInteger; const AOffset:Integer); protected procedure Load(const AData:TDataItem; const Children:Boolean); override; end; diff --git a/src/delphi/BI.Data.pas b/src/delphi/BI.Data.pas index d611c8d..eba952a 100644 --- a/src/delphi/BI.Data.pas +++ b/src/delphi/BI.Data.pas @@ -23,7 +23,7 @@ interface {$ENDIF} System.Classes, System.SysUtils, - BI.Arrays, BI.Streams, BI.Expression; + BI.Arrays, BI.Expression; type TDataKind=(dkInt32, @@ -60,7 +60,7 @@ TMissingData=record {$IFDEF AUTOREFCOUNT}[Weak]{$ENDIF} IData : TDataItem; - procedure DestroyStats; + procedure DestroyStats; inline; // Returns True if the data value at Index position is null (missing) function GetItem(const Index:TInteger):Boolean; inline; @@ -88,6 +88,7 @@ TDataArrayHelper=record helper for TDataArray function Count:Integer; inline; procedure Delete(const Index:Integer); procedure Exchange(const A,B:Integer); + function Exists(const AData:TDataItem):Boolean; inline; function Find(const AName:String):TDataItem; function IndexOf(const AData:TDataItem):Integer; overload; function IndexOf(const AName:String):Integer; overload; @@ -276,6 +277,9 @@ TMasterDetail=record procedure DestroyStats; + function FindMapRow(const AMap:TDataMap; const ARow:TLoopInteger; out AIndex:TNativeInteger):Boolean; overload; + function FindMapRow(const ARow:TLoopInteger; out AIndex:TNativeInteger):Boolean; overload; inline; + function GetItem(const AName:String):TDataItem; inline; {$IFNDEF FPC} @@ -394,7 +398,7 @@ TMasterDetail=record procedure CreateMasterIndex; procedure Delete(const Row:TInteger; const ACount:TInteger=1); - function DataToString(const Index:TInteger):String; + function DataToString(const Index:TInteger):String; overload; function FindInMap(const Index:TInteger; out ABin:TNativeInteger):Boolean; procedure Finish; function FullName:String; diff --git a/src/delphi/BI.Expression.Filter.pas b/src/delphi/BI.Expression.Filter.pas index 1aef94c..75ea876 100644 --- a/src/delphi/BI.Expression.Filter.pas +++ b/src/delphi/BI.Expression.Filter.pas @@ -1,3 +1,9 @@ +{*********************************************} +{ TeeBI Software Library } +{ TBIFilter class using Expressions } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} unit BI.Expression.Filter; interface @@ -56,18 +62,18 @@ TMonths=class(TFilterPart) property Month[const Index:Integer]:Boolean read Get write Put; default; published - property January:Boolean index 0 read Get write Put; - property February:Boolean index 1 read Get write Put; - property March:Boolean index 2 read Get write Put; - property April:Boolean index 3 read Get write Put; - property May:Boolean index 4 read Get write Put; - property June:Boolean index 5 read Get write Put; - property July:Boolean index 6 read Get write Put; - property August:Boolean index 7 read Get write Put; - property September:Boolean index 8 read Get write Put; - property October:Boolean index 9 read Get write Put; - property November:Boolean index 10 read Get write Put; - property December:Boolean index 11 read Get write Put; + property January:Boolean index 0 read Get write Put default False; + property February:Boolean index 1 read Get write Put default False; + property March:Boolean index 2 read Get write Put default False; + property April:Boolean index 3 read Get write Put default False; + property May:Boolean index 4 read Get write Put default False; + property June:Boolean index 5 read Get write Put default False; + property July:Boolean index 6 read Get write Put default False; + property August:Boolean index 7 read Get write Put default False; + property September:Boolean index 8 read Get write Put default False; + property October:Boolean index 9 read Get write Put default False; + property November:Boolean index 10 read Get write Put default False; + property December:Boolean index 11 read Get write Put default False; end; TWeekdays=class(TFilterPart) @@ -80,19 +86,41 @@ TWeekdays=class(TFilterPart) protected procedure SetWeekDays(const Value:TBooleanArray); public + procedure Assign(Source:TPersistent); override; + function Filter:TLogicalExpression; + property Weekday[const Index:Integer]:Boolean read Get write Put; default; + published + property Monday:Boolean index 0 read Get write Put default False; + property Tuesday:Boolean index 1 read Get write Put default False; + property Wednesday:Boolean index 2 read Get write Put default False; + property Thursday:Boolean index 3 read Get write Put default False; + property Friday:Boolean index 4 read Get write Put default False; + property Saturday:Boolean index 5 read Get write Put default False; + property Sunday:Boolean index 6 read Get write Put default False; + end; + + TDateTimeSelected=class(TFilterPart) + private + FDateTime : TDateTime; + FEnabled: Boolean; + FPart : TDateTimePart; + FValue : Integer; + + procedure SetDateTime(const Value: TDateTime); + procedure SetEnabled(const Value: Boolean); + procedure SetPart(const Value: TDateTimePart); + procedure SetValue(const Value: Integer); + public procedure Assign(Source:TPersistent); override; - property Weekday[const Index:Integer]:Boolean read Get write Put; default; + function Filter:TLogicalExpression; published - property Monday:Boolean index 0 read Get write Put; - property Tuesday:Boolean index 1 read Get write Put; - property Wednesday:Boolean index 2 read Get write Put; - property Thursday:Boolean index 3 read Get write Put; - property Friday:Boolean index 4 read Get write Put; - property Saturday:Boolean index 5 read Get write Put; - property Sunday:Boolean index 6 read Get write Put; + property DateTime:TDateTime read FDateTime write SetDateTime; + property Enabled:Boolean read FEnabled write SetEnabled default False; + property Part:TDateTimePart read FPart write SetPart default TDateTimePart.None; + property Value:Integer read FValue write SetValue default 0; end; TDateTimeFilterStyle=(All,Custom,Today,Yesterday,Tomorrow,This,Last,Next); @@ -100,10 +128,11 @@ TWeekdays=class(TFilterPart) TDateTimeFilter=class(TFilterPart) private FMonths : TMonths; + FPeriod: TDateTimeSpan; + FQuantity : Integer; + FSelected: TDateTimeSelected; // "Style N Period" = "Last 10 Weeks" FStyle : TDateTimeFilterStyle; FWeekdays : TWeekdays; - FPeriod: TDateTimeSpan; - FQuantity : Integer; // "Style N Period" = "Last 10 Weeks" function GetFrom: TDateTime; function GetTo: TDateTime; @@ -111,6 +140,7 @@ TDateTimeFilter=class(TFilterPart) procedure SetMonths(const Value: TMonths); procedure SetPeriod(const Value: TDateTimeSpan); procedure SetQuantity(const Value: Integer); + procedure SetSelected(const Value: TDateTimeSelected); procedure SetStyle(const Value: TDateTimeFilterStyle); procedure SetTo(const Value: TDateTime); procedure SetWeedays(const Value: TWeekdays); @@ -128,6 +158,7 @@ TDateTimeFilter=class(TFilterPart) property Months:TMonths read FMonths write SetMonths; property Period:TDateTimeSpan read FPeriod write SetPeriod default TDateTimeSpan.None; property Quantity:Integer read FQuantity write SetQuantity default 1; + property Selected:TDateTimeSelected read FSelected write SetSelected; property Style:TDateTimeFilterStyle read FStyle write SetStyle default TDateTimeFilterStyle.All; property Weekdays:TWeekdays read FWeekdays write SetWeedays; end; @@ -149,28 +180,50 @@ TBooleanFilter=class(TFilterPart) property IncludeFalse:Boolean read GetFalse write SetFalse default False; end; + TNumericFilter=class(TFilterPart) + private + FFrom : TNumericValue; + FSelected : TNumericValue; + FTo : TNumericValue; + + procedure SetFrom(const Value: TNumericValue); + procedure SetSelected(const Value: TNumericValue); + procedure SetTo(const Value: TNumericValue); + protected + function RangeFilter:TLogicalExpression; + public + Constructor Create(const AItem:TFilterItem); + Destructor Destroy; override; + + procedure Assign(Source:TPersistent); override; + + function Filter:TLogicalExpression; + published + property FromValue:TNumericValue read FFrom write SetFrom; + property Selected:TNumericValue read FSelected write SetSelected; + property ToValue:TNumericValue read FTo write SetTo; + end; + TFilterItem=class(TDataCollectionItem) private FBool : TBooleanFilter; FDateTime : TDateTimeFilter; FEnabled: Boolean; FExcluded: TStringList; - FFrom : TNumericValue; + FExpression : TLogicalExpression; FIncluded: TStringList; - FTo : TNumericValue; + FNumeric : TNumericFilter; procedure DoChanged(Sender:TObject); function GetFilter: TLogicalExpression; function MainData:TDataItem; function NewLogical(const AOperand:TLogicalOperand):TLogicalExpression; - function NumericFilter: TLogicalExpression; procedure SetBool(const Value: TBooleanFilter); procedure SetDateTime(const Value: TDateTimeFilter); procedure SetEnabled(const Value: Boolean); procedure SetExcluded(const Value: TStringList); procedure SetIncluded(const Value: TStringList); - procedure SetFrom(const Value: TNumericValue); - procedure SetTo(const Value: TNumericValue); + procedure SetNumeric(const Value: TNumericFilter); procedure TryAdd(const AText:String; const A,B:TStrings); protected procedure Changed; override; @@ -183,15 +236,15 @@ TFilterItem=class(TDataCollectionItem) procedure ExcludeText(const AText:String; const Add:Boolean=True); procedure IncludeText(const AText:String; const Add:Boolean=True); + property Expression:TLogicalExpression read FExpression write FExpression; property Filter:TLogicalExpression read GetFilter; published property BoolFilter:TBooleanFilter read FBool write SetBool; property DateTime:TDateTimeFilter read FDateTime write SetDateTime; property Enabled:Boolean read FEnabled write SetEnabled default True; property Excluded:TStringList read FExcluded write SetExcluded; - property FromValue:TNumericValue read FFrom write SetFrom; property Included:TStringList read FIncluded write SetIncluded; - property ToValue:TNumericValue read FTo write SetTo; + property Numeric:TNumericFilter read FNumeric write SetNumeric; end; TBIFilter=class; @@ -218,9 +271,6 @@ TBIFilter=class(TPersistent) FItems: TFilterItems; FText : String; - // Temporary during csLoading - IFilter : String; - procedure Changed; function Get(const AIndex: Integer): TFilterItem; function IsItemsStored: Boolean; @@ -238,7 +288,9 @@ TBIFilter=class(TPersistent) procedure Assign(Source:TPersistent); override; - function Add(const AData:TDataItem):TFilterItem; inline; + function Add(const AData:TDataItem):TFilterItem; overload; inline; + function Add(const AExpression:TLogicalExpression):TFilterItem; overload; inline; + procedure Clear; function Custom:TLogicalExpression; function Filter:TLogicalExpression; diff --git a/src/delphi/BI.Expression.pas b/src/delphi/BI.Expression.pas index ddc37e1..07d9682 100644 --- a/src/delphi/BI.Expression.pas +++ b/src/delphi/BI.Expression.pas @@ -32,11 +32,22 @@ EExpressionParse=class(Exception) TExpression=class; - TResolveProc={$IFNDEF FPC}reference to{$ENDIF} function(const S:String; IsFunction:Boolean):TExpression; + TResolveProc= + {$IFDEF FPC} + function(const S:String; IsFunction:Boolean):TExpression of object; + {$ELSE} + reference to function(const S:String; IsFunction:Boolean):TExpression; + {$ENDIF} + TErrorProc={$IFNDEF FPC}reference to{$ENDIF} function(const APos:Integer; const AMessage:String):Boolean; TExpressionProc=procedure(const Item:TExpression) of object; TExpression=class abstract + {$IFDEF FPC} + private + function NilFunction(const S:String; IsFunction:Boolean):TExpression; + {$ENDIF} + public class var Null:TData; @@ -218,6 +229,8 @@ TLogicalExpression=class(TBaseLogicalExpression) const ARight:TExpression); overload; procedure Assign(const Source: TExpression); override; + class function Join(const AOld,ANew:TLogicalExpression; + const AOperand:TLogicalOperand=TLogicalOperand.&And):TLogicalExpression; static; function Value:TData; override; function ToString:String; override; end; @@ -323,8 +336,10 @@ TDateTimePartHelper=record helper for TDateTimePart var QuarterFormat:String; class function AllToText:String; static; - class function Max:Integer; static; function AsString(const Index:Integer):String; + function High:Integer; + function Low: Integer; + class function Max:Integer; static; function ToString:String; overload; class function ToString(const Index:Integer):String; overload; inline; static; end; @@ -393,4 +408,21 @@ TTextOperandExpression=class(TExpression) end; *) + // Value := Condition ? Then : Else + TIfExpression=class(TExpression) + public + Condition : TLogicalExpression; + + ThenExpression, + ElseExpression : TExpression; + + Constructor Create(const ACondition:TLogicalExpression; const AThen,AElse:TExpression); + Destructor Destroy; override; + + procedure Assign(const Source:TExpression); override; + + function ToString:String; override; + function Value:TData; override; + end; + implementation diff --git a/src/delphi/BI.FPC.pas b/src/delphi/BI.FPC.pas index e833272..324b6e6 100644 --- a/src/delphi/BI.FPC.pas +++ b/src/delphi/BI.FPC.pas @@ -12,6 +12,11 @@ interface SysUtils, Classes, Graphics, StreamEx; type + TProc=procedure(const Value:T); + TProc=procedure(const Value1:T; const Value2:V); + + TObjectProc=procedure({const} Value:T) of object; + TStopWatch=record private Time : Int64; @@ -77,13 +82,32 @@ TZipFile=class TStreamReader=class(StreamEx.TStreamReader) public - Constructor Create(const AFileName:String); + Constructor CreateFile(const AFileName:String); function EndOfStream:Boolean; end; TAlphaColor=TColor; - + //TAlphaColor=type Cardinal; + + TColorRec = packed record + A, B, G, R: Byte; + end; + + TAlphaColorRec=packed record + public + A, B, G, R: Byte; + + const + Alpha = 0; + Green = $8000; + Red = $FF; + Yellow = $FFFF; + Null = $00000000; + end; + + TAlphaColors=TAlphaColorRec; + function IsQuoted(const S:String):Boolean; function SplitString(const S,Delimiter:String):TStringArray; diff --git a/src/delphi/BI.Languages.English.pas b/src/delphi/BI.Languages.English.pas index 55b002d..241eed7 100644 --- a/src/delphi/BI.Languages.English.pas +++ b/src/delphi/BI.Languages.English.pas @@ -2,7 +2,17 @@ interface +const + TeeBI_Version=20160613; + TeeBI_VersionString='v1 20160613'; + TeeBI_VersionMode='(BETA 14)'; + TeeBI_Description='TeeBI'; + TeeBI_CopyRight='Copyright '+{$IFDEF LCL}'(C)'{$ELSE}'©'{$ENDIF}+' 2015-2016 by Steema Software'; + var + BIMsg_About:String = 'About TeeBI...'; + BIMsg_Edit:String = 'Edit...'; + // DataItem BIMsg_DataItem_ChildNotFound:String = 'Error: Child data: %s not found'; BIMsg_CannotAccessData:String = 'Cannot access data: %s from: %s'; @@ -122,4 +132,11 @@ interface BIMsg_ServerAlreadyRunning:String = 'BIWeb Server is already running.'; BIMsg_ServerSureToClose:String = 'Are you sure to close this server? (There are %d active conections)'; + // Misc + BIMsg_Enabled:String = 'Enabled'; + + // BIVisual Dashboard Template + BIMsg_LoadTemplate:String = 'Load Dashboard Template'; + BIMsg_UnknownData:String = 'Error Unknown Data: %s'; + implementation diff --git a/src/delphi/BI.MapReduce.pas b/src/delphi/BI.MapReduce.pas index 81f265d..aa9ee49 100644 --- a/src/delphi/BI.MapReduce.pas +++ b/src/delphi/BI.MapReduce.pas @@ -62,9 +62,6 @@ interface TIndices=TInt64Array; TMapReduce=class - private - class function DataFrom(const AData:TArray):TDataItem; static; - class function KindOf:TDataKind; static; public class var Parallel : Boolean; @@ -83,9 +80,17 @@ TMapReduce=class end; TMapReduce=class(TMapReduce) + private + {$IFDEF FPC} + type + TArrayOfT=Array of T; + {$ENDIF} + + class function DataFrom(const AData:{$IFDEF FPC}TArrayOfT{$ELSE}TArray{$ENDIF}):TDataItem; static; + class function KindOf:TDataKind; static; public type - TMapProc=reference to function(const Index:TKeyIndex):T; + TMapProc={$IFNDEF FPC}reference to{$ENDIF} function(const Index:TKeyIndex):T; class function ForAll(const AData:TDataItem; const AMap:TMapProc):TDataItem; static; end; @@ -93,19 +98,28 @@ TMapReduce=class(TMapReduce) TMapReduce=class(TMapReduce) public type - TReduceProc=reference to function(const Key:T; const List:TIndices):V; + TReduceProc={$IFNDEF FPC}reference to{$ENDIF} function(const Key:T; const List:TIndices):V; private + {$IFDEF FPC} + type + TArrayOfT=Array of T; + TArrayOfV=Array of V; + TArrayOfIndices=Array of TIndices; + {$ENDIF} + class function DoMap(const AFrom,ATo:TNativeInteger; const AMap: TMapReduce.TMapProc; - var AKey:TArray; - var AItems:TArray): TDataItem; static; + var AKey:{$IFDEF FPC}TArrayOfT{$ELSE}TArray{$ENDIF}; + var AItems:{$IFDEF FPC}TArrayOfIndices{$ELSE}TArray{$ENDIF}): TDataItem; static; - class function DoReduce(const AKey:TArray; + class function DoReduce(const AKey:{$IFDEF FPC}TArrayOfT{$ELSE}TArray{$ENDIF}; const AReduce:TReduceProc; - const AItems:TArray):TArray; static; + const AItems:{$IFDEF FPC}TArrayOfIndices{$ELSE}TArray{$ENDIF}): + {$IFDEF FPC}TArrayOfV{$ELSE}TArray{$ENDIF}; static; - class function TableFrom(const AKey:TArray; const AValue:TArray):TDataItem; static; + class function TableFrom(const AKey:{$IFDEF FPC}TArrayOfT{$ELSE}TArray{$ENDIF}; + const AValue:{$IFDEF FPC}TArrayOfV{$ELSE}TArray{$ENDIF}):TDataItem; static; public class function From(const AData:TDataItem; const AMap:TMapReduce.TMapProc; diff --git a/src/delphi/BI.Persist.pas b/src/delphi/BI.Persist.pas index f7e7eb2..7fceb39 100644 --- a/src/delphi/BI.Persist.pas +++ b/src/delphi/BI.Persist.pas @@ -19,11 +19,21 @@ interface uses - System.Classes, System.SysUtils, System.Types, BI.Data, BI.Arrays, BI.Streams; + System.Classes, System.SysUtils, + {$IFDEF FPC} + BI.FPC, + {$ENDIF} + BI.Data, BI.Arrays, BI.Streams; type TBIError=function(const Sender:TObject; const Error:String):Boolean of object; - TBIErrorProc={$IFNDEF FPC}reference to{$ENDIF} function(const Sender:TObject; const Error:String):Boolean; + + TBIErrorProc= + {$IFDEF FPC} + function(const Sender:TObject; const Error:String):Boolean of object; + {$ELSE} + reference to function(const Sender:TObject; const Error:String):Boolean; + {$ENDIF} TBIProgress=procedure(const Sender:TObject; const Percent:Single; var Cancel:Boolean) of object; @@ -53,11 +63,27 @@ TRefreshSettings=record Enabled : Boolean; end; + TDataDefinition=class; + + TDatabaseDefinition=class(TPersistent) + private + IDefinition : TDataDefinition; + + function GetSystem: Boolean; + procedure SetSystem(const Value: Boolean); + function GetViews: Boolean; + procedure SetViews(const Value: Boolean); + published + property IncludeViews:Boolean read GetViews write SetViews default False; + property IncludeSystem:Boolean read GetSystem write SetSystem default False; + end; + // Abstract class with all settings necessary to import a given data TDataDefinitionKind=(Files,Database,Web,Unknown); TDataDefinition=class(TBaseDataImporter) private + FDatabase : TDatabaseDefinition; FFileName : String; FOnError : TBIError; @@ -65,12 +91,17 @@ TDataDefinition=class(TBaseDataImporter) ILoading : Boolean; + function GetCalcStats: Boolean; function GetKind: TDataDefinitionKind; + function GetParallel: Boolean; procedure GetRefreshSettings; function GetStrings:TStrings; function GetValue(const Index: String): String; + procedure PrecalculateStats(const AData:TDataArray); + procedure SetCalcStats(const AValue: Boolean); procedure SetFileName(const Value: String); procedure SetKind(const Value: TDataDefinitionKind); + procedure SetParallel(const AValue: Boolean); procedure SetValue(const Index: String; const Value: String); procedure SetStrings(const Value: TStrings); procedure TryLoadDetailRelations(const AData:TDataArray); @@ -92,10 +123,12 @@ TDataDefinition=class(TBaseDataImporter) var Store : String; + Constructor Create(AOwner:TComponent); override; + Constructor FromFile(const AOwner:TComponent; const AFileName:String); Destructor Destroy; override; - function AsBoolean(const Key:String):Boolean; + function AsBoolean(const Key:String; const ADefault:Boolean=True):Boolean; class procedure CreateFile(const FileName:String; const Kind:TDataDefinitionKind); @@ -115,6 +148,9 @@ TDataDefinition=class(TBaseDataImporter) function NextRefresh:TDateTime; class procedure SetMasters(const AData:TDataItem; const Items:TStrings); static; + property AsDatabase:TDatabaseDefinition read FDatabase; + property CalcStats:Boolean read GetCalcStats write SetCalcStats default False; + property Parallel:Boolean read GetParallel write SetParallel default False; property Value[const Index:String]:String read GetValue write SetValue; default; published property Kind:TDataDefinitionKind read GetKind write SetKind default TDataDefinitionKind.Unknown; @@ -142,7 +178,7 @@ TDataImporter=class(TDataProvider) public Constructor CreateDefinition(const AStore:String; const ADefinition:TDataDefinition); virtual; - function AllData:TStringDynArray; virtual; abstract; + function AllData:TStringArray; virtual; abstract; function GetDefinition(const AName:String):TDataDefinition; virtual; abstract; class function Guess(const Kind:TDataDefinitionKind; const Store:String; @@ -167,7 +203,7 @@ TStore=class class function NameOrDefault(const AName: String): String; class procedure SetDefaultName(const Value: String); static; public - class function AllData(const AStore:String=''):TStringDynArray; overload; static; + class function AllData(const AStore:String=''):TStringArray; overload; static; class function DefinitionOf(const Name:string):String; overload; static; class function DefinitionOf(const AStore,Name: string): String; overload; static; @@ -222,7 +258,7 @@ TStores=class public class procedure Add(const AName,AOrigin:String); static; class procedure AllTo(const Items:TStrings); static; - class function All(const APart:Integer=0):TStringDynArray; static; + class function All(const APart:Integer=0):TStringArray; static; class procedure ChangeName(const AOld,ANew:String); static; class procedure ChangePath(const AName,AOrigin:String); static; class function Count:Integer; static; @@ -231,7 +267,7 @@ TStores=class class function IndexOf(const AName:String):Integer; static; class function NewName:String; static; class procedure Remove(const AName:String); static; - class procedure Save(const S:TStringDynArray); overload; static; + class procedure Save(const S:TStringArray); overload; static; class procedure Save(const Index:Integer; const AName,AOrigin:String); overload; static; end; diff --git a/src/delphi/BI.Schedule.pas b/src/delphi/BI.Schedule.pas index 71cfc19..772818a 100644 --- a/src/delphi/BI.Schedule.pas +++ b/src/delphi/BI.Schedule.pas @@ -12,7 +12,7 @@ interface System.Classes; type - TWork=reference to procedure(const Item:TObject); + TWork={$IFNDEF FPC}reference to{$ENDIF} procedure(const Item:TObject); TScheduler=class; diff --git a/src/delphi/BI.Store.Component.pas b/src/delphi/BI.Store.Component.pas index c7b0461..9a9df84 100644 --- a/src/delphi/BI.Store.Component.pas +++ b/src/delphi/BI.Store.Component.pas @@ -9,7 +9,7 @@ interface uses - System.Classes, System.Types, + System.Classes, {$IFNDEF FPC} System.Generics.Collections, {$ENDIF} @@ -35,6 +35,7 @@ TComponentImporter=class(TBaseDataImporter) IDataLink : TDataLink; ILoading : Boolean; + class function IgnoreError(const Sender:TObject; const Error:String):Boolean; procedure SetSource(const Value: TComponent); class function TryFromStrings(const ASource:TComponent):TDataItem; protected @@ -49,7 +50,6 @@ TComponentImporter=class(TBaseDataImporter) class var Plugins : TList{$IFNDEF FPC}{$ENDIF}; - Constructor Create(AOwner:TComponent); override; Destructor Destroy; override; procedure Refresh; diff --git a/src/delphi/BI.Streams.pas b/src/delphi/BI.Streams.pas index c905737..56aa7b6 100644 --- a/src/delphi/BI.Streams.pas +++ b/src/delphi/BI.Streams.pas @@ -56,6 +56,9 @@ TBIStreamer=class procedure InitBuffer(const BufferSize:Integer); public + const + DefaultBuffer=2048; + Constructor Create(const AStream:TStream); property Raw:Boolean read IRaw; @@ -71,11 +74,14 @@ TBIReader=class(TBIStreamer) public Version : Integer; - Constructor Create(const AStream:TStream; const BufferSize:Integer); + Constructor Create(const AStream:TStream; + const BufferSize:Integer=TBIStreamer.DefaultBuffer); + Destructor Destroy; override; procedure Read(var Value; Size:Integer); function ReadBoolean:Boolean; inline; + procedure ReadComponent(const Value:TComponent); inline; function ReadDate: TDateTime; inline; function ReadDouble: Double; {$IFNDEF FPC}inline;{$ENDIF} function ReadFloat: Extended; inline; @@ -95,14 +101,16 @@ TBIWriter=class(TBIStreamer) procedure SetPosition(const Value: Int64); procedure WriteBuffer; public - Constructor Create(const AStream:TStream; const BufferSize:Integer; - const Raw:Boolean); + Constructor Create(const AStream:TStream; + const BufferSize:Integer=TBIStreamer.DefaultBuffer; + const Raw:Boolean=False); Destructor Destroy; override; procedure FlushBuffer; procedure Write(const Value; Size:Integer); procedure WriteBoolean(const Value: Boolean); inline; + procedure WriteComponent(const Value:TComponent); inline; procedure WriteDate(const Value: TDateTime); inline; procedure WriteDouble(const Value: Double); inline; procedure WriteFloat(const Value: Extended); inline; diff --git a/src/delphi/BI.Summary.pas b/src/delphi/BI.Summary.pas index 690dbae..8a80028 100644 --- a/src/delphi/BI.Summary.pas +++ b/src/delphi/BI.Summary.pas @@ -336,7 +336,7 @@ TSummaryExpression=class(TExpression) procedure Assign(const Source:TExpression); override; class function FromString(const AItem:TSummaryItem; const AExpression:String):TSummaryExpression; static; - function GetExpression(const AData:TDataItem):TExpression; + function GetExpression(const AData:TDataItem):TLogicalExpression; function ToString:String; override; function Value:TData; override; end; @@ -362,7 +362,7 @@ TSummaryFilter=class(TDataExpression) procedure Clear; - function GetExpression(const AData:TDataItem):TExpression; + function GetExpression(const AData:TDataItem):TLogicalExpression; function ToString:String; override; end; diff --git a/src/delphi/BI.Tree.pas b/src/delphi/BI.Tree.pas index 70e1659..9c274ef 100644 --- a/src/delphi/BI.Tree.pas +++ b/src/delphi/BI.Tree.pas @@ -119,7 +119,7 @@ TNode=class property Items:TArray> read FItems; public type - TNodeProc=reference to procedure(const Item:TNode); + TNodeProc={$IFNDEF FPC}reference to{$ENDIF} procedure(const Item:TNode); var Data : T; diff --git a/src/delphi/BI.UI.Colors.pas b/src/delphi/BI.UI.Colors.pas index fb9a094..6b6f785 100644 --- a/src/delphi/BI.UI.Colors.pas +++ b/src/delphi/BI.UI.Colors.pas @@ -8,33 +8,15 @@ interface -{$IFNDEF FPC} uses - System.UITypes; -{$ENDIF} - -type {$IFDEF FPC} - TColorRec = packed record - A, B, G, R: Byte; - end; - - TAlphaColor=type Cardinal; - - TAlphaColorRec=packed record - public - A, B, G, R: Byte; - - const - Alpha = 0; - Green = $8000; - Red = $FF; - Yellow = $FFFF; - end; - - TAlphaColors=TAlphaColorRec; + BI.FPC + {$ELSE} + System.UITypes {$ENDIF} + ; +type TColorItem=record public Color : TAlphaColor; diff --git a/src/delphi/BI.UI.pas b/src/delphi/BI.UI.pas index 944c6d5..227e614 100644 --- a/src/delphi/BI.UI.pas +++ b/src/delphi/BI.UI.pas @@ -29,6 +29,7 @@ TCommonUI=record class procedure AddInfo(const AData:TDataItem; const AItems:TStrings); static; class procedure AddKinds(const AItems:TStrings); static; class function BytesToString(const Bytes: Int64): String; static; + class function MSecToString(const MSec:Int64):String; static; class function ToBooleanString(const Bool:Boolean):String; static; class function UniqueName(const AComponent:TComponent):String; static; end; diff --git a/src/delphi/BI.Web.FPC.pas b/src/delphi/BI.Web.FPC.pas index f57ab9c..3fa476e 100644 --- a/src/delphi/BI.Web.FPC.pas +++ b/src/delphi/BI.Web.FPC.pas @@ -10,7 +10,7 @@ interface uses System.Classes, System.SysUtils, - fpHttpClient, BI.Web; + fpHttpClient, BI.Web, BI.Persist; type EHttpAbort=class(Exception); @@ -20,15 +20,17 @@ TBIFPCWeb=class(TBIHttp) FHttp : TFPHttpClient; // FPC //IMaxWork : Int64; - - procedure DoProgress(const ACurrent,ATotal:Int64); public Constructor Create(const AOwner:TComponent); override; Destructor Destroy; override; + class function FTP(const ADef:TDataDefinition):TBIFtp; override; + procedure Get(const AURL:String; const AStream:TStream); overload; override; function Get(const AURL:String):String; overload; override; + class function Parse(const AURL:String):TWebURL; override; procedure SetProxy(const AProxy:TWebProxy); override; + procedure SetTimeout(const ATimeout:Integer); override; end; implementation diff --git a/src/delphi/BI.Web.Indy.pas b/src/delphi/BI.Web.Indy.pas index 674f545..e070a79 100644 --- a/src/delphi/BI.Web.Indy.pas +++ b/src/delphi/BI.Web.Indy.pas @@ -22,7 +22,6 @@ TBIIndy=class(TBIHttp) IMaxWork : Int64; - procedure DoProgress(const ACurrent,ATotal:Int64); procedure WorkBegin(ASender: TObject; AWorkMode: TWorkMode; AWorkCountMax: Int64); procedure WorkEnd(ASender: TObject; AWorkMode: TWorkMode); procedure Work(ASender: TObject; AWorkMode: TWorkMode; AWorkCount: Int64); diff --git a/src/delphi/BI.Web.pas b/src/delphi/BI.Web.pas index a50021b..bbf52c0 100644 --- a/src/delphi/BI.Web.pas +++ b/src/delphi/BI.Web.pas @@ -51,6 +51,8 @@ TBIHttp=class abstract private class var FOnProgress : TBIHttpProgress; + protected + procedure DoProgress(const ACurrent,ATotal:Int64); public class var Engine : TBIHttpClass; diff --git a/src/delphi/FMX/BI.FMX.Component.pas b/src/delphi/FMX/BI.FMX.Component.pas index ff8a843..7b82c83 100644 --- a/src/delphi/FMX/BI.FMX.Component.pas +++ b/src/delphi/FMX/BI.FMX.Component.pas @@ -29,6 +29,7 @@ interface System.Classes, BI.Data, BI.Store.Component; type + {$IFNDEF FPC} {$IF CompilerVersion>=23} [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 {$IF CompilerVersion>=25}or pidiOSSimulator or pidiOSDevice{$ENDIF} @@ -36,6 +37,7 @@ interface {$IF CompilerVersion>=29}or pidiOSDevice64{$ENDIF} )] {$ENDIF} + {$ENDIF} TControlImporter=class(TComponentImporter) protected function DoImport(const AComponent: TComponent):TDataItem; override; diff --git a/src/delphi/FMX/BI.FMX.Dashboard.Chart.pas b/src/delphi/FMX/BI.FMX.Dashboard.Chart.pas index ef6fdb7..ee0c3d7 100644 --- a/src/delphi/FMX/BI.FMX.Dashboard.Chart.pas +++ b/src/delphi/FMX/BI.FMX.Dashboard.Chart.pas @@ -24,7 +24,7 @@ TScreenChartRender=class(TScreenRender) class procedure FinishChart(const AChart:TBITChart; const AItem:TDashboardItem); static; protected function CanRefreshData(const AControl:TControl):Boolean; override; - function NewControl(const AKind:String; const AItem:TDashboardItem):TControl; override; + function NewControl(const AKind:TPanelKind; const AItem:TDashboardItem):TControl; override; {$IFDEF FMX} procedure PostAddControl(const AControl:TControl; const AItem:TDashboardItem); override; diff --git a/src/delphi/FMX/BI.FMX.Dashboard.pas b/src/delphi/FMX/BI.FMX.Dashboard.pas index f0ea00a..cf3e991 100644 --- a/src/delphi/FMX/BI.FMX.Dashboard.pas +++ b/src/delphi/FMX/BI.FMX.Dashboard.pas @@ -10,7 +10,14 @@ interface uses - System.Classes, System.UITypes, + System.Classes, + + {$IFDEF FPC} + BI.FPC, + {$ELSE} + System.UITypes, + {$ENDIF} + {$IFDEF FMX} FMX.Controls, FMX.Layouts, FMX.ExtCtrls, FMX.TabControl, @@ -24,11 +31,11 @@ interface FMX.StdCtrls, FMX.Types, FMX.Objects, {$ELSE} - VCL.Controls, VCL.StdCtrls, VCL.ExtCtrls, VCL.Graphics, VCL.ComCtrls, + WinApi.Messages, VCL.Controls, VCL.StdCtrls, VCL.ExtCtrls, VCL.Graphics, VCL.ComCtrls, VCL.Forms, {$ENDIF} - BI.Data, BI.Expression, BI.Dashboard; + BI.Data, BI.Expression, BI.Dashboard, BI.Dashboard.Layouts; type {$IFDEF FMX} @@ -89,31 +96,23 @@ TTargetControl=record TTargetControls=Array of TTargetControl; - TTargetControlsHelper=record helper for TTargetControls - public - function Add(const AName:String; const AControl:TControl; const ALayout:TLayoutItem):Integer; - function Count:Integer; inline; - function FindControl(const AName:String):TControl; overload; - function FindControl(const AItem:TLayoutItem):TControl; overload; - function FindLayout(const AControl:TControl):TLayoutItem; - end; - //procedure AddControl(const AControl:TControl; const APosition:String; const AItem:TDashboardItem); procedure AddToParent(const AControl:TControl; const AParent:TWinControl; const AItem:TDashboardItem); procedure ButtonsChange(Sender:TObject); procedure ChangedVariable(const Sender:TChangeListener; const AValue:TExpression); - procedure Clear; procedure ComboChange(Sender:TObject); procedure ControlClick(Sender: TObject); + function ControlOwner:TComponent; function CreateLayoutClass(const AClass:TControlClass):TPanel; class function CreateSplitter(const AAlign:TAlign; const AParent:TWinControl):TSplitter; static; procedure EmitDashboard(const AItem:TDashboardItem; const APosition:String); - procedure EmitLayout(const ALayout:TLayoutItem; const ShowNames:Boolean=False); + procedure EmitLayout(const ALayout:TLayoutItem; const Splitters:Boolean=True; + const ShowNames:Boolean=False); function GetTarget(const AName:String; const AItem:TDashboardItem): TObject; @@ -133,35 +132,47 @@ TTargetControlsHelper=record helper for TTargetControls procedure TrackBarChange(Sender: TObject); protected - procedure AddListener(const AName:String; const ADataIndex:Integer); override; + procedure AddListener(const AName:String; const ASource:TObject); override; function CanRefreshData(const AControl:TControl):Boolean; virtual; function CreateControl(const ALayout:TLayoutItem; const AParent:TWinControl; const APrefix:String; - const ShowNames:Boolean):TWinControl; + const Splitters,ShowNames:Boolean):TWinControl; function CreatePanel(const ABack:TAlphaColor):TLayoutPanel; overload; function CreatePanel:TLayoutPanel; overload; inline; - function EmitPanel(const AItem:TDashboardItem; const AKind:String; const APosition:String=''):TControl; - function EnsurePanelData(const APanel:TBIPanel):TDataItem; + function EmitPanel(const AItem:TDashboardItem; const AKind:TPanelKind; const APosition:String=''):TControl; + function EnsurePanelData(const APanel:TCustomBIPanel):TDataItem; class function GetItemOf(const Sender:TControl):TDashboardItem; static; - function NewControl(const AKind:String; const AItem:TDashboardItem):TControl; virtual; + function NewControl(const AKind:TPanelKind; const AItem:TDashboardItem):TControl; virtual; function ParentRender:TScreenRender; procedure PostAddControl(const AControl:TControl; const AItem:TDashboardItem); virtual; procedure RadioChange(Sender: TObject); virtual; public Targets : TTargetControls; + type + TTargetControlsHelper=record helper for TTargetControls + public + function Add(const AName:String; const AControl:TControl; const ALayout:TLayoutItem):Integer; + function Count:Integer; inline; + function FindControl(const AName:String):TControl; overload; + function FindControl(const AItem:TLayoutItem):TControl; overload; + function FindLayout(const AControl:TControl):TLayoutItem; + end; + + procedure Clear; override; procedure Init(const ADashboard:TDashboard; const ALayout:String=''; const AParams:TStrings=nil); override; procedure Finish; override; procedure Emit(const ADashboard:TDashboard; const AItem:Integer; const APosition:String); override; - procedure SetNested(const AItem:TLayoutItem; const AName:String; const ShowNames:Boolean); + procedure SetNested(const AItem:TLayoutItem; const AName:String; const Splitters,ShowNames:Boolean); property Control:TBIVisual read FControl write FControl; end; + {$IFNDEF FPC} {$IF CompilerVersion>=23} [ComponentPlatformsAttribute(pidWin32 or pidWin64 {$IFDEF FMX} @@ -172,20 +183,50 @@ TTargetControlsHelper=record helper for TTargetControls {$ENDIF} )] {$ENDIF} + {$ENDIF} TBIVisual=class({$IFDEF FMX}TScrollBox{$ELSE}TScrollingWinControl{$ENDIF}) - public - type - TSizeUnits=(Pixels, Percent); - private - FTemplate : TBITemplate; + FCurrent : TDashboard; FRender: TRender; + FTemplate : TBITemplate; FVariables : TVariables; ICanResize : Boolean; + ICurrent : String; // temporary during loading + + {$IFNDEF FMX} + procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED; + {$ENDIF} + + procedure DoResize(const AParent:TWinControl); + function GetDashboards: TDashboards; + function GetDataItems: TVisualDataItems; // GetData already exists in FMX + function GetLayouts: TLayouts; + function GetPanels: TPanels; + + {$IFDEF FMX} + procedure MovedSplitter(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); + {$ELSE} + procedure MovedSplitter(Sender: TObject); + {$ENDIF} + + procedure ReadCurrent(Reader: TReader); + procedure SetCurrent(const Value: TDashboard); + procedure SetDashboards(const Value: TDashboards); + procedure SetDataItems(const Value: TVisualDataItems); // SetData already exists in FMX + procedure SetLayouts(const Value: TLayouts); + procedure SetPanels(const Value: TPanels); + procedure SetRender(const Value: TRender); + procedure SetTemplate(const Value: TBITemplate); + procedure TryFreeTemplate; + procedure TryGenerateCurrent; + procedure TryResize; + procedure WriteCurrent(Writer: TWriter); type TSizedControl=record + private + procedure TryRefreshItem; public // [Weak] Control : TControl; @@ -195,20 +236,23 @@ TSizedControl=record Height : Single; WidthUnits, - HeightUnits : TSizeUnits; + HeightUnits : TUnits; procedure ReCalc; function Resized:Boolean; - procedure SetSize(const AWidth,AHeight:String); + procedure SetSize(const AWidth:Single; + const AWidthUnits:TUnits; + const AHeight:Single; + const AHeightUnits:TUnits); end; TSizedControls=Array of TSizedControl; TSizedControlsHelper=record helper for TSizedControls public - procedure Add(const AControl:TControl; const AWidth,AHeight:String); + procedure Add(const AControl:TControl; const AWidth,AHeight:TBICoordinate); procedure CheckSize(const AItem:TLayoutItem; const AControl:TControl); overload; - procedure CheckSize(const APanel:TBIPanel; const AControl:TControl); overload; + procedure CheckSize(const APanel:TCustomBIPanel; const AControl:TControl); overload; procedure CheckSize(const AItem:TDashboardItem; const AControl:TControl); overload; function FindSplitter(const ASplitter:TSplitter):Integer; function IndexOf(const AControl:TControl):Integer; @@ -219,19 +263,11 @@ TSizedControlsHelper=record helper for TSizedControls var ISizedControls : TSizedControls; - procedure DoResize(const AParent:TWinControl); - - {$IFDEF FMX} - procedure MovedSplitter(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); - {$ELSE} - procedure MovedSplitter(Sender: TObject); - {$ENDIF} - - procedure SetRender(const Value: TRender); - procedure SetTemplate(const Value: TBITemplate); - procedure TryFreeTemplate; protected procedure Clear; + procedure DefineProperties(Filer: TFiler); override; + function GetChildOwner: TComponent; override; + procedure Loaded; override; procedure Resize; override; public class var @@ -240,20 +276,16 @@ TSizedControlsHelper=record helper for TSizedControls Constructor Create(AOwner:TComponent); override; Destructor Destroy; override; - // Single Dashboard - procedure Generate(const ADashboard:TDashboard; const ALayout:String=''); overload; + // Single Dashboard, use first one if ADashboard is nil + procedure Generate(const ADashboard:TDashboard=nil; const ALayout:String=''); overload; // Single Panel procedure Generate(const APanel:TBIPanel); overload; - // Use first Dashboard, if it exists - procedure Generate; overload; - procedure ResizeLayout; property Render:TRender read FRender write SetRender; property Template:TBITemplate read FTemplate write SetTemplate; - published property Align; property Anchors; @@ -321,6 +353,13 @@ TSizedControlsHelper=record helper for TSizedControls {$ENDIF} {$ENDIF} + property Dashboard:TDashboard read FCurrent write SetCurrent stored False; + + property Dashboards : TDashboards read GetDashboards write SetDashboards; + property Data : TVisualDataItems read GetDataItems write SetDataItems; + property Layouts : TLayouts read GetLayouts write SetLayouts; + property Panels : TPanels read GetPanels write SetPanels; + { Events } {$IFDEF FMX} diff --git a/src/delphi/FMX/BI.FMX.DataManager.fmx b/src/delphi/FMX/BI.FMX.DataManager.fmx index 9d84897..237e66b 100644 --- a/src/delphi/FMX/BI.FMX.DataManager.fmx +++ b/src/delphi/FMX/BI.FMX.DataManager.fmx @@ -333,8 +333,8 @@ object DataManager: TDataManager Size.PlatformDefault = False TabOrder = 0 Visible = False - Viewport.Width = 394.000000000000000000 - Viewport.Height = 100.000000000000000000 + Viewport.Width = 398.000000000000000000 + Viewport.Height = 104.000000000000000000 end object Layout1: TLayout Align = Top @@ -368,8 +368,8 @@ object DataManager: TDataManager Size.Height = 73.000000000000000000 Size.PlatformDefault = False TabOrder = 6 - Viewport.Width = 253.000000000000000000 - Viewport.Height = 69.000000000000000000 + Viewport.Width = 257.000000000000000000 + Viewport.Height = 73.000000000000000000 end object BImportNow: TButton Position.X = 16.000000000000000000 diff --git a/src/delphi/FMX/BI.FMX.Grid.pas b/src/delphi/FMX/BI.FMX.Grid.pas index b432673..55a6549 100644 --- a/src/delphi/FMX/BI.FMX.Grid.pas +++ b/src/delphi/FMX/BI.FMX.Grid.pas @@ -61,6 +61,7 @@ TBIGrid = class(TBIDataControl) IPlugin : TBIGridPlugin; procedure CreateNewDataSet; + function GetCurrentRow: Integer; procedure SetAlternate(const Value: TAlternateColor); procedure SetPlugin(const Value: TBIGridPlugin); procedure SetDataSet(const Value: TBIDataSet); @@ -82,6 +83,7 @@ TBIGrid = class(TBIDataControl) property DataSet:TBIDataSet read IDataSet write SetDataSet; property Plugin:TBIGridPlugin read IPlugin write SetPlugin; + property CurrentRow:Integer read GetCurrentRow; published property Alternate:TAlternateColor read FAlternate write SetAlternate; end; @@ -102,8 +104,8 @@ TUICommon=record AlignBottom=TAlignLayout.{$IFDEF HASFMX20}alBottom{$ELSE}Bottom{$ENDIF}; class procedure AddForm(const AForm: TCommonCustomForm; const AParent: TFmxObject); static; - class function Ask(const ATitle,ACaption:String; var AValue:String):Boolean; static; class function AutoTest:Boolean; static; + class function Input(const ATitle,ACaption,ADefault:String; out AValue:String):Boolean; static; class procedure LoadPosition(const AForm:TCommonCustomForm; const Key:String); static; class procedure Popup(const APopup:TPopupMenu; const AControl:TControl); static; class procedure SavePosition(const AForm:TCommonCustomForm; const Key:String); static; diff --git a/src/delphi/FMX/BI.FMX.Tree.TeeTree.pas b/src/delphi/FMX/BI.FMX.Tree.TeeTree.pas new file mode 100644 index 0000000..0d2cac6 --- /dev/null +++ b/src/delphi/FMX/BI.FMX.Tree.TeeTree.pas @@ -0,0 +1,85 @@ +{*********************************************} +{ TeeBI Software Library } +{ Plugin TBITree class for VCL TeeTree } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.FMX.Tree.TeeTree; +{$DEFINE FMX} + +interface + +uses + System.Classes, + TeeTree, + + {$IFDEF FMX} + FMX.Controls, BI.FMX.Tree, + {$ELSE} + VCL.Controls, BI.VCL.Tree, + {$ENDIF} + + BI.Arrays; + +type + TTeeTreePlugin=class(TBITreePlugin) + private + FAllowDelete : Boolean; + FTree : TTree; + FTreeOnChange : TNotifyEvent; + FTreeOnCheck : TNotifyEvent; + + procedure TreeChecked(Sender:TObject); + procedure TreeClick(Sender:TObject); + + {$IFDEF FMX} + procedure TreeKeyUp(Sender: TObject; var Key: Word; var KeyChar: WideChar; Shift: TShiftState); + {$ELSE} + procedure TreeKeyUp(Sender:TObject; var Key:Word; Shift:TShiftState); + {$ENDIF} + + protected + procedure BeginUpdating; override; + procedure Clear(const ANode:TBITreeNode=nil); override; + procedure ClearData(const ANode:TBITreeNode); override; + procedure EndUpdating; override; + function GetAllowDelete: Boolean; override; + function GetControl:TControl; override; + function GetCount:Integer; override; + function GetNode(const AIndex:Integer):TBITreeNode; override; + function GetOnChange: TNotifyEvent; override; + function GetOnCheck: TNotifyEvent; override; + function GetSelected:TBITreeNode; override; + function GetSelectedData: TBITreePlugin.TNodeData; override; + function NodeAt(const X,Y:Integer):TBITreeNode; override; + function SelectedText:String; override; + procedure SetAllowDelete(const Value: Boolean); override; + procedure SetData(const ANode: TBITreeNode; const AData: TObject); override; + procedure SetOnChange(const Value: TNotifyEvent); override; + procedure SetOnCheck(const Value: TNotifyEvent); override; + procedure SetSelected(const Value: TBITreeNode); override; + public + Constructor Create(const AOwner:TComponent); override; + + function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; override; + function ChildrenCount(const ANode:TBITreeNode):Integer; override; + + function DataOf(const ANode:TBITreeNode):TObject; override; + procedure Expand(const AIndex:Integer); override; + procedure Expand(const ANode:TBITreeNode; const DoExpand:Boolean=True; const Recursive:Boolean=False); override; + + function Find(const ATag:TObject; const AIndex:Integer):TBITreeNode; override; + function FirstNode:TBITreeNode; override; + function IsChecked(const ANode:TBITreeNode):Boolean; override; + function IsExpanded(const ANode:TBITreeNode):Boolean; override; + function NewNode(const AParent:TBITreeNode; const AText:String; + const ATag:TObject=nil; const AIndex:TInteger=-1):TBITreeNode; override; + function NextNode(const ANode:TBITreeNode):TBITreeNode; override; + function ParentOf(const ANode:TBITreeNode):TBITreeNode; override; + procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); override; + procedure SetText(const ANode:TBITreeNode; const Value:String); override; + function SiblingIndex(const ANode:TBITreeNode):Integer; override; + function TextOf(const ANode:TBITreeNode):String; override; + end; + +implementation diff --git a/src/delphi/FMX/BI.FMX.Tree.TreeView.pas b/src/delphi/FMX/BI.FMX.Tree.TreeView.pas index ae8c1fe..ebcd88e 100644 --- a/src/delphi/FMX/BI.FMX.Tree.TreeView.pas +++ b/src/delphi/FMX/BI.FMX.Tree.TreeView.pas @@ -1,3 +1,9 @@ +{*********************************************} +{ TeeBI Software Library } +{ Plugin TBITree class for FMX TTreeView } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} unit BI.FMX.Tree.TreeView; interface @@ -10,23 +16,52 @@ interface type TBITreeViewPlugin=class(TBITreePlugin) private + FAllowDelete : Boolean; FTree : TTreeView; protected - procedure Clear; override; + procedure BeginUpdating; override; + procedure Clear(const ANode:TBITreeNode=nil); override; + procedure ClearData(const ANode:TBITreeNode); override; + procedure EndUpdating; override; + function GetAllowDelete: Boolean; override; function GetControl:TControl; override; function GetCount:Integer; override; + function GetNode(const AIndex:Integer):TBITreeNode; override; function GetOnChange: TNotifyEvent; override; + function GetOnCheck: TNotifyEvent; override; function GetSelected:TBITreeNode; override; function GetSelectedData:TBITreePlugin.TNodeData; override; + function NodeAt(const X,Y:Integer):TBITreeNode; override; + function SelectedText:String; override; + procedure SetAllowDelete(const Value: Boolean); override; + procedure SetData(const ANode:TBITreeNode; const AData:TObject); override; procedure SetOnChange(const Value: TNotifyEvent); override; + procedure SetOnCheck(const Value: TNotifyEvent); override; + procedure SetSelected(const Value: TBITreeNode); override; public Constructor Create(const AOwner:TComponent); override; + function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; override; + function ChildrenCount(const ANode:TBITreeNode):Integer; override; + + function DataOf(const ANode:TBITreeNode):TObject; override; + procedure Expand(const AIndex:Integer); override; + procedure Expand(const ANode:TBITreeNode; const DoExpand:Boolean=True; const Recursive:Boolean=False); override; + function Find(const ATag:TObject; const AIndex:Integer):TBITreeNode; override; + function FirstNode:TBITreeNode; override; + function IsChecked(const ANode:TBITreeNode):Boolean; override; + function IsExpanded(const ANode:TBITreeNode):Boolean; override; function NewNode(const AParent:TBITreeNode; const AText:String; const ATag:TObject=nil; const AIndex:TInteger=-1):TBITreeNode; override; + function NextNode(const ANode:TBITreeNode):TBITreeNode; override; + function ParentOf(const ANode:TBITreeNode):TBITreeNode; override; + procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); override; + procedure SetText(const ANode:TBITreeNode; const Value:String); override; + function SiblingIndex(const ANode:TBITreeNode):Integer; override; + function TextOf(const ANode:TBITreeNode):String; override; end; implementation diff --git a/src/delphi/FMX/BI.FMX.Tree.pas b/src/delphi/FMX/BI.FMX.Tree.pas index 6354bd6..e0bc8a7 100644 --- a/src/delphi/FMX/BI.FMX.Tree.pas +++ b/src/delphi/FMX/BI.FMX.Tree.pas @@ -34,27 +34,24 @@ TNodeData=class public Index : TInteger; - //{$IFDEF AUTOREFCOUNT}[Weak]{$ENDIF} - //Node : Integer; - {$IFDEF AUTOREFCOUNT}[Weak]{$ENDIF} Tag : TObject; end; - private - IDatas : Array of TNodeData; - protected + IData : Array of TNodeData; + FOnDelete : TNotifyEvent; procedure BeginUpdating; virtual; abstract; - procedure Clear; virtual; abstract; - procedure ClearData; + procedure Clear(const ANode:TBITreeNode=nil); virtual; abstract; + procedure ClearData; overload; + procedure ClearData(const ANode:TBITreeNode); overload; virtual; abstract; + procedure DeleteData(const AData:TNodeData); procedure EndUpdating; virtual; abstract; function GetAllowDelete: Boolean; virtual; abstract; function GetControl:TControl; virtual; abstract; function GetCount:Integer; virtual; abstract; - function GetData(const ANode:TBITreeNode):TObject; virtual; abstract; function GetNode(const AIndex:Integer):TBITreeNode; virtual; abstract; function GetOnChange: TNotifyEvent; virtual; abstract; function GetOnCheck: TNotifyEvent; virtual; abstract; @@ -75,6 +72,7 @@ TNodeData=class function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; virtual; abstract; function ChildrenCount(const ANode:TBITreeNode):Integer; virtual; abstract; + function DataOf(const ANode:TBITreeNode):TObject; virtual; abstract; procedure Expand(const AIndex:Integer); overload; virtual; abstract; procedure Expand(const ANode:TBITreeNode; @@ -87,6 +85,7 @@ TNodeData=class function NextNode(const ANode:TBITreeNode):TBITreeNode; virtual; abstract; function IsChecked(const ANode:TBITreeNode):Boolean; virtual; abstract; + function IsExpanded(const ANode:TBITreeNode):Boolean; virtual; abstract; function NewNode(const AParent:TBITreeNode; const AText:String; const ATag:TObject=nil; @@ -95,6 +94,7 @@ TNodeData=class function ParentOf(const ANode:TBITreeNode):TBITreeNode; virtual; abstract; procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); virtual; abstract; + procedure SetText(const ANode:TBITreeNode; const Value:String); virtual; abstract; function SiblingIndex(const ANode:TBITreeNode):Integer; virtual; abstract; function TextOf(const ANode:TBITreeNode):String; virtual; abstract; @@ -112,6 +112,7 @@ TBITreePluginClass=class of TBITreePlugin; // Generic Tree control that fills nodes from TDataItem relationships + {$IFNDEF FPC} {$IF CompilerVersion>=23} [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 {$IF CompilerVersion>=25}or pidiOSSimulator or pidiOSDevice{$ENDIF} @@ -119,6 +120,7 @@ TBITreePluginClass=class of TBITreePlugin; {$IF CompilerVersion>=29}or pidiOSDevice64{$ENDIF} )] {$ENDIF} + {$ENDIF} TBITree=class(TBIDataControl) public type @@ -136,14 +138,17 @@ TBITreeNodes=class private FNodes : TBITreeNodes; FOnDeleting : TNotifyEvent; + FPlugin : TBITreePlugin; + function GetAllowDelete: Boolean; function GetOnChange: TNotifyEvent; function GetSelected: TBITreeNode; + procedure SetAllowDelete(const Value: Boolean); procedure SetOnChange(const Value: TNotifyEvent); procedure SetSelected(const Value: TBITreeNode); - function GetAllowDelete: Boolean; - procedure SetAllowDelete(const Value: Boolean); + procedure SetPlugin(const APlugin:TBITreePlugin); protected + procedure ChangeDragMode; procedure DeletedNode(Sender:TObject); procedure Loaded; override; procedure SetDataDirect(const Value: TDataItem); override; @@ -151,9 +156,6 @@ TBITreeNodes=class class var Engine : TBITreePluginClass; - var - Plugin : TBITreePlugin; - Constructor Create(AOwner:TComponent); override; Destructor Destroy; override; @@ -162,7 +164,9 @@ TBITreeNodes=class procedure BeginUpdating; // <-- not "BeginUpdate" due to conflict with FMX - procedure Clear; + procedure ChangePlugin(const APluginClass:TBITreePluginClass); + + procedure Clear(const ANode:TBITreeNode=nil); function DataOf(const ANode:TBITreeNode):TObject; procedure EndUpdating; @@ -178,6 +182,8 @@ TBITreeNodes=class procedure FillStore(const AStore:String); procedure FillStores; + function Find(const AText:String):TBITreeNode; + function NodeAt(const X,Y:Integer):TBITreeNode; function ParentOf(const ANode:TBITreeNode):TBITreeNode; @@ -188,6 +194,7 @@ TBITreeNodes=class procedure SetNodeData(const ANode:TBITreeNode; const AData:TObject); property Nodes:TBITreeNodes read FNodes; + property Plugin:TBITreePlugin read FPlugin write SetPlugin; property Selected:TBITreeNode read GetSelected write SetSelected; published property AllowDelete:Boolean read GetAllowDelete write SetAllowDelete default False; diff --git a/src/delphi/Packages/DclFmxTeeBI.dpk b/src/delphi/Packages/DclFmxTeeBI.dpk index 5b6db70..0d71aa8 100644 --- a/src/delphi/Packages/DclFmxTeeBI.dpk +++ b/src/delphi/Packages/DclFmxTeeBI.dpk @@ -38,6 +38,7 @@ requires designide; contains + TeeBIFMXAbout in 'TeeBIFMXAbout.pas' {AboutBI}, TeeBIFMXRegister in 'TeeBIFMXRegister.pas'; end. diff --git a/src/delphi/Packages/FMXTeeBI.dpk b/src/delphi/Packages/FMXTeeBI.dpk index 0cd2b2c..004b89f 100644 --- a/src/delphi/Packages/FMXTeeBI.dpk +++ b/src/delphi/Packages/FMXTeeBI.dpk @@ -49,6 +49,7 @@ contains BI.FMX.DataEditor in '..\FMX\BI.FMX.DataEditor.pas' {DataEditor}, BI.FMX.DataManager in '..\FMX\BI.FMX.DataManager.pas' {DataManager}, BI.FMX.Editor.Column in '..\FMX\BI.FMX.Editor.Column.pas' {ColumnEditor}, + BI.FMX.Editor.Grid in '..\FMX\BI.FMX.Editor.Grid.pas' {BIGridEditor}, BI.FMX.Status in '..\FMX\BI.FMX.Status.pas' {StoreStatus}, BI.FMX.Editor.Stores in '..\FMX\BI.FMX.Editor.Stores.pas' {StoreEditor}, BI.FMX.Visualizer in '..\FMX\BI.FMX.Visualizer.pas', diff --git a/src/delphi/Packages/TeeBI.dpk b/src/delphi/Packages/TeeBI.dpk index 8eaa256..14f3f6d 100644 --- a/src/delphi/Packages/TeeBI.dpk +++ b/src/delphi/Packages/TeeBI.dpk @@ -41,6 +41,8 @@ contains BI.Arrays in '..\BI.Arrays.pas', BI.Compare in '..\BI.Compare.pas', BI.Dashboard in '..\BI.Dashboard.pas', + BI.Dashboard.Layouts in '..\BI.Dashboard.Layouts.pas', + BI.Dashboard.Loader in '..\BI.Dashboard.Loader.pas', BI.DataSource in '..\BI.DataSource.pas', BI.Expression in '..\BI.Expression.pas', BI.Expression.Filter in '..\BI.Expression.Filter.pas', @@ -65,6 +67,7 @@ contains BI.Data.JSON in '..\BI.Data.JSON.pas', BI.Data.Excel in '..\BI.Data.Excel.pas', BI.Data.Rtti in '..\BI.Data.Rtti.pas', + BI.Data.SingleRecord in '..\BI.Data.SingleRecord.pas', BI.Data.SQL in '..\BI.Data.SQL.pas', BI.Data.XML in '..\BI.Data.XML.pas', BI.Data.JSON.Standard in '..\BI.Data.JSON.Standard.pas', diff --git a/src/delphi/Packages/TeeBIAbout.dfm b/src/delphi/Packages/TeeBIAbout.dfm index 428f751a11ee8cdebff85d8ee411d9c6c3a1edde..f8284671d0f77b382ce4ee47b65baf12a1061700 100644 GIT binary patch delta 26 icmey%{+E5jMn*>U$(tA*8O1h#VH9U%G?~o9{1E_yWeB+d delta 26 icmey%{+E5jMn*=p$(tA*8AUgLVH9U%G@8uA{1E_yJqWb` diff --git a/src/delphi/Packages/TeeBIAbout.pas b/src/delphi/Packages/TeeBIAbout.pas index 1abe079..6e79a7d 100644 --- a/src/delphi/Packages/TeeBIAbout.pas +++ b/src/delphi/Packages/TeeBIAbout.pas @@ -32,13 +32,6 @@ TAboutBI = class(TForm) class procedure Show(const AOwner:TComponent); end; -const - TeeBI_Version=20160523; - TeeBI_VersionString='v1 20160526'; - TeeBI_VersionMode='(BETA 13)'; - TeeBI_Description='TeeBI'; - TeeBI_CopyRight='Copyright '+{$IFDEF LCL}'(C)'{$ELSE}'©'{$ENDIF}+' 2015-2016 by Steema Software'; - procedure TeeBIGotoURL(const Handle:HWND; const URL:String); implementation diff --git a/src/delphi/Packages/TeeBIFMXAbout.pas b/src/delphi/Packages/TeeBIFMXAbout.pas new file mode 100644 index 0000000..bc47b79 --- /dev/null +++ b/src/delphi/Packages/TeeBIFMXAbout.pas @@ -0,0 +1,46 @@ +unit TeeBIFMXAbout; + +interface + +uses + System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, + FMX.Types, FMX.Controls, FMX.Forms, + + {$IF CompilerVersion<26} // Cannot use FireMonkeyVersion<21 (or 21_0) + {$DEFINE HASFMX20} + {$ENDIF} + + {$IFNDEF HASFMX20} + FMX.Graphics, + {$ENDIF} + + {$IF CompilerVersion<28} + {$DEFINE HASFMX21} + {$ENDIF} + + {$IFNDEF HASFMX21} + FMX.Controls.Presentation, + {$ENDIF} + + FMX.Dialogs, FMX.StdCtrls, FMX.Layouts, FMX.Objects; + +type + TAboutBI = class(TForm) + Image1: TImage; + Layout1: TLayout; + Button1: TButton; + Label1: TLabel; + Label2: TLabel; + LCopyright: TLabel; + LVersion: TLabel; + procedure Button1Click(Sender: TObject); + procedure FormCreate(Sender: TObject); + procedure Label1Click(Sender: TObject); + private + { Private declarations } + public + { Public declarations } + class procedure Show(const AOwner:TComponent); + end; + +implementation diff --git a/src/delphi/Packages/VCLTeeBI.dpk b/src/delphi/Packages/VCLTeeBI.dpk index 0e47af9..1e7b1c5 100644 --- a/src/delphi/Packages/VCLTeeBI.dpk +++ b/src/delphi/Packages/VCLTeeBI.dpk @@ -72,6 +72,11 @@ contains BI.VCL.Visualizer in '..\VCL\BI.VCL.Visualizer.pas', BI.VCL.Editor.Visualizer in '..\VCL\BI.VCL.Editor.Visualizer.pas' {VisualizerEditor}, BI.VCL.Dashboard in '..\VCL\BI.VCL.Dashboard.pas', + BI.VCL.Editor.Template in '..\VCL\BI.VCL.Editor.Template.pas' {TemplateEditor}, + BI.VCL.Editor.Template.Data in '..\VCL\BI.VCL.Editor.Template.Data.pas' {DataGallery}, + BI.VCL.Editor.Template.Panels in '..\VCL\BI.VCL.Editor.Template.Panels.pas' {PanelGallery}, + BI.VCL.Editor.Template.Layouts in '..\VCL\BI.VCL.Editor.Template.Layouts.pas' {LayoutGallery}, + BI.VCL.Designer.Template.Layouts in '..\VCL\BI.VCL.Designer.Template.Layouts.pas' {LayoutDesigner}, BI.VCL.Tree in '..\VCL\BI.VCL.Tree.pas', BI.VCL.Tree.TreeView in '..\VCL\BI.VCL.Tree.TreeView.pas'; diff --git a/src/delphi/VCL/BI.VCL.Component.pas b/src/delphi/VCL/BI.VCL.Component.pas index 674c6a3..729bd60 100644 --- a/src/delphi/VCL/BI.VCL.Component.pas +++ b/src/delphi/VCL/BI.VCL.Component.pas @@ -29,6 +29,7 @@ interface System.Classes, BI.Data, BI.Store.Component; type + {$IFNDEF FPC} {$IF CompilerVersion>=23} [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 {$IF CompilerVersion>=25}or pidiOSSimulator or pidiOSDevice{$ENDIF} @@ -36,6 +37,7 @@ interface {$IF CompilerVersion>=29}or pidiOSDevice64{$ENDIF} )] {$ENDIF} + {$ENDIF} TControlImporter=class(TComponentImporter) protected function DoImport(const AComponent: TComponent):TDataItem; override; diff --git a/src/delphi/VCL/BI.VCL.Dashboard.Chart.pas b/src/delphi/VCL/BI.VCL.Dashboard.Chart.pas index fc5e9b1..a5b56c0 100644 --- a/src/delphi/VCL/BI.VCL.Dashboard.Chart.pas +++ b/src/delphi/VCL/BI.VCL.Dashboard.Chart.pas @@ -24,7 +24,7 @@ TScreenChartRender=class(TScreenRender) class procedure FinishChart(const AChart:TBITChart; const AItem:TDashboardItem); static; protected function CanRefreshData(const AControl:TControl):Boolean; override; - function NewControl(const AKind:String; const AItem:TDashboardItem):TControl; override; + function NewControl(const AKind:TPanelKind; const AItem:TDashboardItem):TControl; override; {$IFDEF FMX} procedure PostAddControl(const AControl:TControl; const AItem:TDashboardItem); override; diff --git a/src/delphi/VCL/BI.VCL.Dashboard.pas b/src/delphi/VCL/BI.VCL.Dashboard.pas index 076a948..c56d9e4 100644 --- a/src/delphi/VCL/BI.VCL.Dashboard.pas +++ b/src/delphi/VCL/BI.VCL.Dashboard.pas @@ -10,7 +10,14 @@ interface uses - System.Classes, System.UITypes, + System.Classes, + + {$IFDEF FPC} + BI.FPC, + {$ELSE} + System.UITypes, + {$ENDIF} + {$IFDEF FMX} FMX.Controls, FMX.Layouts, FMX.ExtCtrls, FMX.TabControl, @@ -24,11 +31,11 @@ interface FMX.StdCtrls, FMX.Types, FMX.Objects, {$ELSE} - VCL.Controls, VCL.StdCtrls, VCL.ExtCtrls, VCL.Graphics, VCL.ComCtrls, + WinApi.Messages, VCL.Controls, VCL.StdCtrls, VCL.ExtCtrls, VCL.Graphics, VCL.ComCtrls, VCL.Forms, {$ENDIF} - BI.Data, BI.Expression, BI.Dashboard; + BI.Data, BI.Expression, BI.Dashboard, BI.Dashboard.Layouts; type {$IFDEF FMX} @@ -89,31 +96,23 @@ TTargetControl=record TTargetControls=Array of TTargetControl; - TTargetControlsHelper=record helper for TTargetControls - public - function Add(const AName:String; const AControl:TControl; const ALayout:TLayoutItem):Integer; - function Count:Integer; inline; - function FindControl(const AName:String):TControl; overload; - function FindControl(const AItem:TLayoutItem):TControl; overload; - function FindLayout(const AControl:TControl):TLayoutItem; - end; - //procedure AddControl(const AControl:TControl; const APosition:String; const AItem:TDashboardItem); procedure AddToParent(const AControl:TControl; const AParent:TWinControl; const AItem:TDashboardItem); procedure ButtonsChange(Sender:TObject); procedure ChangedVariable(const Sender:TChangeListener; const AValue:TExpression); - procedure Clear; procedure ComboChange(Sender:TObject); procedure ControlClick(Sender: TObject); + function ControlOwner:TComponent; function CreateLayoutClass(const AClass:TControlClass):TPanel; class function CreateSplitter(const AAlign:TAlign; const AParent:TWinControl):TSplitter; static; procedure EmitDashboard(const AItem:TDashboardItem; const APosition:String); - procedure EmitLayout(const ALayout:TLayoutItem; const ShowNames:Boolean=False); + procedure EmitLayout(const ALayout:TLayoutItem; const Splitters:Boolean=True; + const ShowNames:Boolean=False); function GetTarget(const AName:String; const AItem:TDashboardItem): TObject; @@ -133,35 +132,47 @@ TTargetControlsHelper=record helper for TTargetControls procedure TrackBarChange(Sender: TObject); protected - procedure AddListener(const AName:String; const ADataIndex:Integer); override; + procedure AddListener(const AName:String; const ASource:TObject); override; function CanRefreshData(const AControl:TControl):Boolean; virtual; function CreateControl(const ALayout:TLayoutItem; const AParent:TWinControl; const APrefix:String; - const ShowNames:Boolean):TWinControl; + const Splitters,ShowNames:Boolean):TWinControl; function CreatePanel(const ABack:TAlphaColor):TLayoutPanel; overload; function CreatePanel:TLayoutPanel; overload; inline; - function EmitPanel(const AItem:TDashboardItem; const AKind:String; const APosition:String=''):TControl; - function EnsurePanelData(const APanel:TBIPanel):TDataItem; + function EmitPanel(const AItem:TDashboardItem; const AKind:TPanelKind; const APosition:String=''):TControl; + function EnsurePanelData(const APanel:TCustomBIPanel):TDataItem; class function GetItemOf(const Sender:TControl):TDashboardItem; static; - function NewControl(const AKind:String; const AItem:TDashboardItem):TControl; virtual; + function NewControl(const AKind:TPanelKind; const AItem:TDashboardItem):TControl; virtual; function ParentRender:TScreenRender; procedure PostAddControl(const AControl:TControl; const AItem:TDashboardItem); virtual; procedure RadioChange(Sender: TObject); virtual; public Targets : TTargetControls; + type + TTargetControlsHelper=record helper for TTargetControls + public + function Add(const AName:String; const AControl:TControl; const ALayout:TLayoutItem):Integer; + function Count:Integer; inline; + function FindControl(const AName:String):TControl; overload; + function FindControl(const AItem:TLayoutItem):TControl; overload; + function FindLayout(const AControl:TControl):TLayoutItem; + end; + + procedure Clear; override; procedure Init(const ADashboard:TDashboard; const ALayout:String=''; const AParams:TStrings=nil); override; procedure Finish; override; procedure Emit(const ADashboard:TDashboard; const AItem:Integer; const APosition:String); override; - procedure SetNested(const AItem:TLayoutItem; const AName:String; const ShowNames:Boolean); + procedure SetNested(const AItem:TLayoutItem; const AName:String; const Splitters,ShowNames:Boolean); property Control:TBIVisual read FControl write FControl; end; + {$IFNDEF FPC} {$IF CompilerVersion>=23} [ComponentPlatformsAttribute(pidWin32 or pidWin64 {$IFDEF FMX} @@ -172,20 +183,50 @@ TTargetControlsHelper=record helper for TTargetControls {$ENDIF} )] {$ENDIF} + {$ENDIF} TBIVisual=class({$IFDEF FMX}TScrollBox{$ELSE}TScrollingWinControl{$ENDIF}) - public - type - TSizeUnits=(Pixels, Percent); - private - FTemplate : TBITemplate; + FCurrent : TDashboard; FRender: TRender; + FTemplate : TBITemplate; FVariables : TVariables; ICanResize : Boolean; + ICurrent : String; // temporary during loading + + {$IFNDEF FMX} + procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED; + {$ENDIF} + + procedure DoResize(const AParent:TWinControl); + function GetDashboards: TDashboards; + function GetDataItems: TVisualDataItems; // GetData already exists in FMX + function GetLayouts: TLayouts; + function GetPanels: TPanels; + + {$IFDEF FMX} + procedure MovedSplitter(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); + {$ELSE} + procedure MovedSplitter(Sender: TObject); + {$ENDIF} + + procedure ReadCurrent(Reader: TReader); + procedure SetCurrent(const Value: TDashboard); + procedure SetDashboards(const Value: TDashboards); + procedure SetDataItems(const Value: TVisualDataItems); // SetData already exists in FMX + procedure SetLayouts(const Value: TLayouts); + procedure SetPanels(const Value: TPanels); + procedure SetRender(const Value: TRender); + procedure SetTemplate(const Value: TBITemplate); + procedure TryFreeTemplate; + procedure TryGenerateCurrent; + procedure TryResize; + procedure WriteCurrent(Writer: TWriter); type TSizedControl=record + private + procedure TryRefreshItem; public // [Weak] Control : TControl; @@ -195,20 +236,23 @@ TSizedControl=record Height : Single; WidthUnits, - HeightUnits : TSizeUnits; + HeightUnits : TUnits; procedure ReCalc; function Resized:Boolean; - procedure SetSize(const AWidth,AHeight:String); + procedure SetSize(const AWidth:Single; + const AWidthUnits:TUnits; + const AHeight:Single; + const AHeightUnits:TUnits); end; TSizedControls=Array of TSizedControl; TSizedControlsHelper=record helper for TSizedControls public - procedure Add(const AControl:TControl; const AWidth,AHeight:String); + procedure Add(const AControl:TControl; const AWidth,AHeight:TBICoordinate); procedure CheckSize(const AItem:TLayoutItem; const AControl:TControl); overload; - procedure CheckSize(const APanel:TBIPanel; const AControl:TControl); overload; + procedure CheckSize(const APanel:TCustomBIPanel; const AControl:TControl); overload; procedure CheckSize(const AItem:TDashboardItem; const AControl:TControl); overload; function FindSplitter(const ASplitter:TSplitter):Integer; function IndexOf(const AControl:TControl):Integer; @@ -219,19 +263,11 @@ TSizedControlsHelper=record helper for TSizedControls var ISizedControls : TSizedControls; - procedure DoResize(const AParent:TWinControl); - - {$IFDEF FMX} - procedure MovedSplitter(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single); - {$ELSE} - procedure MovedSplitter(Sender: TObject); - {$ENDIF} - - procedure SetRender(const Value: TRender); - procedure SetTemplate(const Value: TBITemplate); - procedure TryFreeTemplate; protected procedure Clear; + procedure DefineProperties(Filer: TFiler); override; + function GetChildOwner: TComponent; override; + procedure Loaded; override; procedure Resize; override; public class var @@ -240,20 +276,16 @@ TSizedControlsHelper=record helper for TSizedControls Constructor Create(AOwner:TComponent); override; Destructor Destroy; override; - // Single Dashboard - procedure Generate(const ADashboard:TDashboard; const ALayout:String=''); overload; + // Single Dashboard, use first one if ADashboard is nil + procedure Generate(const ADashboard:TDashboard=nil; const ALayout:String=''); overload; // Single Panel procedure Generate(const APanel:TBIPanel); overload; - // Use first Dashboard, if it exists - procedure Generate; overload; - procedure ResizeLayout; property Render:TRender read FRender write SetRender; property Template:TBITemplate read FTemplate write SetTemplate; - published property Align; property Anchors; @@ -321,6 +353,13 @@ TSizedControlsHelper=record helper for TSizedControls {$ENDIF} {$ENDIF} + property Dashboard:TDashboard read FCurrent write SetCurrent stored False; + + property Dashboards : TDashboards read GetDashboards write SetDashboards; + property Data : TVisualDataItems read GetDataItems write SetDataItems; + property Layouts : TLayouts read GetLayouts write SetLayouts; + property Panels : TPanels read GetPanels write SetPanels; + { Events } {$IFDEF FMX} diff --git a/src/delphi/VCL/BI.VCL.DataSelect.dfm b/src/delphi/VCL/BI.VCL.DataSelect.dfm index 96a8627..c383268 100644 --- a/src/delphi/VCL/BI.VCL.DataSelect.dfm +++ b/src/delphi/VCL/BI.VCL.DataSelect.dfm @@ -27,6 +27,10 @@ object DataSelector: TDataSelector OnChange = PageControl1Change object TabStore: TTabSheet Caption = 'Store' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end object TabComponent: TTabSheet Caption = 'Component' @@ -100,9 +104,9 @@ object DataSelector: TDataSelector OnClick = BClearClick end end - object PopupMenu2: TPopupMenu - Left = 142 - Top = 312 + object ImportMenu: TPopupMenu + Left = 118 + Top = 40 object Import1: TMenuItem Caption = '&Import' object Database1: TMenuItem diff --git a/src/delphi/VCL/BI.VCL.DataSelect.pas b/src/delphi/VCL/BI.VCL.DataSelect.pas index a74c6da..826c3f2 100644 --- a/src/delphi/VCL/BI.VCL.DataSelect.pas +++ b/src/delphi/VCL/BI.VCL.DataSelect.pas @@ -37,7 +37,7 @@ TDataSelector = class(TForm) BOK: TButton; BCancel: TButton; BClear: TButton; - PopupMenu2: TPopupMenu; + ImportMenu: TPopupMenu; Files1: TMenuItem; Database1: TMenuItem; Web1: TMenuItem; @@ -80,6 +80,9 @@ TDataSelector = class(TForm) class procedure Choose(const AOwner:TComponent; const AEdited:TBIDataControl); overload; static; + class function Choose(const AOwner:TComponent; + const AEdited:TComponent):TDataItem; overload; static; + class function Choose(const AOwner:TComponent; const AEdited:TComponent; out AData:TDataItem; diff --git a/src/delphi/VCL/BI.VCL.DataViewer.dfm b/src/delphi/VCL/BI.VCL.DataViewer.dfm index ee6a536..8f5e867 100644 --- a/src/delphi/VCL/BI.VCL.DataViewer.dfm +++ b/src/delphi/VCL/BI.VCL.DataViewer.dfm @@ -87,7 +87,8 @@ object DataViewer: TDataViewer OnChange = CBViewChange Items.Strings = ( 'Data' - 'Data Map') + 'Data Map' + 'Statistics') end end object PanelItems: TPanel @@ -124,18 +125,6 @@ object DataViewer: TDataViewer Align = alClient BevelOuter = bvNone TabOrder = 0 - object DataGrid: TBIGrid - Left = 0 - Top = 0 - Width = 875 - Height = 356 - Align = alClient - UseDockManager = False - ParentBackground = False - ParentColor = False - TabOrder = 0 - OnDataChange = DataGridDataChange - end object PanelNav: TPanel Left = 0 Top = 356 @@ -143,7 +132,7 @@ object DataViewer: TDataViewer Height = 30 Align = alBottom BevelOuter = bvNone - TabOrder = 1 + TabOrder = 0 object Panel2: TPanel Left = 0 Top = 0 @@ -178,6 +167,58 @@ object DataViewer: TDataViewer TabOrder = 0 end end + object CBRecord: TCheckBox + Left = 380 + Top = 8 + Width = 97 + Height = 17 + Caption = '&Record View' + TabOrder = 2 + OnClick = CBRecordClick + end + end + object Panel5: TPanel + Left = 0 + Top = 0 + Width = 875 + Height = 356 + Align = alClient + Caption = 'Panel5' + TabOrder = 1 + object SplitterRecord: TSplitter + Left = 551 + Top = 1 + Height = 354 + Align = alRight + Visible = False + ExplicitLeft = 440 + ExplicitTop = 128 + ExplicitHeight = 100 + end + object DataGrid: TBIGrid + Left = 1 + Top = 1 + Width = 550 + Height = 354 + Align = alClient + UseDockManager = False + ParentBackground = False + ParentColor = False + TabOrder = 0 + OnDataChange = DataGridDataChange + end + object RecordView: TBIGrid + Left = 554 + Top = 1 + Width = 320 + Height = 354 + Align = alRight + UseDockManager = False + ParentBackground = False + ParentColor = False + TabOrder = 1 + Visible = False + end end end end diff --git a/src/delphi/VCL/BI.VCL.DataViewer.pas b/src/delphi/VCL/BI.VCL.DataViewer.pas index 178069d..59e54a2 100644 --- a/src/delphi/VCL/BI.VCL.DataViewer.pas +++ b/src/delphi/VCL/BI.VCL.DataViewer.pas @@ -49,6 +49,10 @@ TDataViewer = class(TForm) DBNavigator2: TDBNavigator; Panel3: TPanel; Panel4: TPanel; + CBRecord: TCheckBox; + Panel5: TPanel; + RecordView: TBIGrid; + SplitterRecord: TSplitter; procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); procedure CBViewDataClick(Sender: TObject); @@ -62,13 +66,16 @@ TDataViewer = class(TForm) procedure ItemsBeforeDelete(DataSet: TDataSet); procedure ItemsAfterInsert(DataSet: TDataSet); procedure DataGridDataChange(Sender: TObject); + procedure CBRecordClick(Sender: TObject); private { Private declarations } FData : TDataItem; IEditing : Boolean; + DataStats, DataMap : TDataItem; + Tree : TTreeView; procedure CheckPanelDataAlign; diff --git a/src/delphi/VCL/BI.VCL.DataWorkflow.pas b/src/delphi/VCL/BI.VCL.DataWorkflow.pas index 4fc2aa0..e209eeb 100644 --- a/src/delphi/VCL/BI.VCL.DataWorkflow.pas +++ b/src/delphi/VCL/BI.VCL.DataWorkflow.pas @@ -1,3 +1,9 @@ +{*********************************************} +{ TeeBI Software Library } +{ DataWorkflow Editor Dialog } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} unit BI.VCL.DataWorkflow; interface @@ -78,6 +84,7 @@ TBIWorkflowEditor = class(TForm) function NewShape(const AParent:TBITreeNode; const AProvider:TDataProvider; const AName:String):TBITreeNode; overload; + function SetErrorLabel(const Sender:TObject; const Error:String):Boolean; procedure SetWorkflow(const Value: TBIWorkflow); procedure TryRefresh(const ANode:TBITreeNode); protected diff --git a/src/delphi/VCL/BI.VCL.Designer.Template.Layouts.dfm b/src/delphi/VCL/BI.VCL.Designer.Template.Layouts.dfm new file mode 100644 index 0000000..1ad7536 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Designer.Template.Layouts.dfm @@ -0,0 +1,258 @@ +object LayoutDesigner: TLayoutDesigner + Left = 0 + Top = 0 + Caption = 'Template Layout Designer' + ClientHeight = 603 + ClientWidth = 955 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnCreate = FormCreate + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object Splitter1: TSplitter + Left = 222 + Top = 0 + Height = 603 + ExplicitLeft = 80 + end + object PageControl1: TPageControl + Left = 225 + Top = 0 + Width = 730 + Height = 603 + ActivePage = TabSheet1 + Align = alClient + TabOrder = 2 + object TabSheet1: TTabSheet + Caption = 'Preview' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 + object BIVisual1: TBIVisual + Left = 0 + Top = 0 + Width = 722 + Height = 575 + Align = alClient + TabOrder = 0 + Dashboards = <> + Data = <> + Layouts = <> + Panels = <> + end + end + object TabSheet2: TTabSheet + Caption = 'Template' + ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 + object MemoTemplate: TMemo + Left = 0 + Top = 0 + Width = 722 + Height = 575 + Align = alClient + ReadOnly = True + ScrollBars = ssBoth + TabOrder = 0 + WordWrap = False + end + end + end + object GalleryTemplate: TMemo + Left = 320 + Top = 104 + Width = 489 + Height = 281 + Lines.Strings = ( + '{' + ' "dashboards": [' + ' {' + ' "name": "gallery",' + ' "layout": "3x3",' + ' "panels": [' + + ' { "layout": "2 Rows", "type": "text", "text": "Hello", "b' + + 'ack": "Aqua" },' + + ' { "layout": "2 Rows", "type": "text", "text": "World", "b' + + 'ack": "Aqua" }' + ' ]' + ' }' + ' ]' + '}') + TabOrder = 0 + Visible = False + WordWrap = False + end + object PanelLeft: TPanel + Left = 0 + Top = 0 + Width = 222 + Height = 603 + Align = alLeft + BevelOuter = bvNone + TabOrder = 1 + object Splitter2: TSplitter + Left = 0 + Top = 258 + Width = 222 + Height = 3 + Cursor = crVSplit + Align = alTop + ExplicitTop = 217 + ExplicitWidth = 386 + end + object Gallery: TBIVisual + Left = 0 + Top = 261 + Width = 222 + Height = 211 + Align = alClient + TabOrder = 0 + Dashboards = <> + Data = <> + Layouts = <> + Panels = <> + end + object LBLayouts: TListBox + Left = 0 + Top = 41 + Width = 222 + Height = 217 + Align = alTop + DragMode = dmAutomatic + ItemHeight = 13 + TabOrder = 1 + OnClick = LBLayoutsClick + end + object Panel1: TPanel + Left = 0 + Top = 472 + Width = 222 + Height = 131 + Align = alBottom + TabOrder = 2 + object LAlign: TLabel + Left = 8 + Top = 48 + Width = 27 + Height = 13 + Caption = 'Align:' + Enabled = False + end + object Label1: TLabel + Left = 8 + Top = 78 + Width = 42 + Height = 13 + Caption = '&Padding:' + end + object BClear: TButton + Left = 8 + Top = 8 + Width = 75 + Height = 25 + Caption = 'Clear' + Enabled = False + TabOrder = 0 + OnClick = BClearClick + end + object BDelete: TButton + Left = 104 + Top = 8 + Width = 75 + Height = 25 + Caption = 'Delete' + Enabled = False + TabOrder = 1 + OnClick = BDeleteClick + end + object CBAlign: TComboBox + Left = 58 + Top = 45 + Width = 105 + Height = 21 + Style = csDropDownList + Enabled = False + TabOrder = 2 + Items.Strings = ( + 'None' + 'Left' + 'Right' + 'Top' + 'Bottom' + 'Client') + end + object EPadding: TEdit + Left = 58 + Top = 75 + Width = 49 + Height = 21 + TabOrder = 3 + Text = '10' + OnChange = EPaddingChange + end + object UDPadding: TUpDown + Left = 107 + Top = 75 + Width = 16 + Height = 21 + Associate = EPadding + Max = 2000 + Position = 10 + TabOrder = 4 + end + end + object Panel2: TPanel + Left = 0 + Top = 0 + Width = 222 + Height = 41 + Align = alTop + BevelOuter = bvNone + TabOrder = 3 + object Button1: TButton + Left = 9 + Top = 9 + Width = 75 + Height = 25 + Caption = 'Options' + TabOrder = 0 + OnClick = Button1Click + end + end + end + object PopupMenu1: TPopupMenu + Left = 104 + Top = 8 + object Captions1: TMenuItem + Caption = '&Captions' + Checked = True + OnClick = Captions1Click + end + object Colors1: TMenuItem + Caption = 'C&olors' + Checked = True + OnClick = Colors1Click + end + object Frames1: TMenuItem + Caption = '&Frames' + OnClick = Frames1Click + end + object Splitters1: TMenuItem + Caption = '&Splitters' + Checked = True + OnClick = Splitters1Click + end + end +end diff --git a/src/delphi/VCL/BI.VCL.Designer.Template.Layouts.pas b/src/delphi/VCL/BI.VCL.Designer.Template.Layouts.pas new file mode 100644 index 0000000..b9d8485 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Designer.Template.Layouts.pas @@ -0,0 +1,105 @@ +{*********************************************} +{ TeeBI Software Library } +{ Layouts Designer } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.VCL.Designer.Template.Layouts; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, BI.VCL.Dashboard, Vcl.ExtCtrls, + Vcl.Menus, Vcl.StdCtrls, Vcl.ComCtrls, BI.VCL.Tree, + BI.Dashboard, BI.Dashboard.Layouts; + +type + TLayoutDesigner = class(TForm) + Splitter1: TSplitter; + GalleryTemplate: TMemo; + PanelLeft: TPanel; + Gallery: TBIVisual; + LBLayouts: TListBox; + Splitter2: TSplitter; + PageControl1: TPageControl; + TabSheet1: TTabSheet; + BIVisual1: TBIVisual; + TabSheet2: TTabSheet; + MemoTemplate: TMemo; + Panel1: TPanel; + BClear: TButton; + BDelete: TButton; + LAlign: TLabel; + CBAlign: TComboBox; + Panel2: TPanel; + Button1: TButton; + PopupMenu1: TPopupMenu; + Captions1: TMenuItem; + Colors1: TMenuItem; + Frames1: TMenuItem; + Splitters1: TMenuItem; + Label1: TLabel; + EPadding: TEdit; + UDPadding: TUpDown; + procedure FormCreate(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure BClearClick(Sender: TObject); + procedure BDeleteClick(Sender: TObject); + procedure Splitters1Click(Sender: TObject); + procedure Button1Click(Sender: TObject); + procedure Colors1Click(Sender: TObject); + procedure Captions1Click(Sender: TObject); + procedure Frames1Click(Sender: TObject); + procedure EPaddingChange(Sender: TObject); + procedure LBLayoutsClick(Sender: TObject); + private + { Private declarations } + + FOnItemChange : TNotifyEvent; + + Tree : TBITree; + + Hover : TShape; + + procedure AddControls(const AParent:TBITreeNode; const AControl:TWinControl); + procedure CreateHover; + + procedure FillGallery; + procedure FillTree(const ALayout:TLayoutItem); + + procedure BIClick(Sender: TObject); + procedure BIDragOver(Sender, Source: TObject; X, Y: Integer; + State: TDragState; var Accept: Boolean); + procedure BIDragDrop(Sender, Source: TObject; X, Y: Integer); + + function FindNode(const AControl:TControl):TBITreeNode; + + procedure RecreateLayout(const ALayout:TLayoutItem); + procedure RefreshEditor(const APanel:TPanel); + + function ScreenRender:TScreenRender; + + function SelectedPanel:TPanel; + procedure SetEvents(const AControl:TControl); + procedure SetPanelBackColor(Sender:TControl); + procedure SetPanelEvents(const ARender:TScreenRender); + procedure SetSplitterColor(Sender:TControl); + procedure ShowHideSplitter(Sender:TControl); + procedure TreeChange(Sender: TObject); + public + { Public declarations } + + class function Edit(const AOwner:TComponent; + const ALayout:TLayoutItem):Boolean; static; + + class function Embedd(const AOwner:TComponent; + const AParent:TWinControl):TLayoutDesigner; static; + + procedure Refresh(const ALayout:TLayoutItem); + function SelectedItem:TPanel; + + property OnItemChange:TNotifyEvent read FOnItemChange write FOnItemChange; + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Editor.BIGrid.dfm b/src/delphi/VCL/BI.VCL.Editor.BIGrid.dfm index d294eb9..a60f098 100644 --- a/src/delphi/VCL/BI.VCL.Editor.BIGrid.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.BIGrid.dfm @@ -25,8 +25,6 @@ object BIGridEditor: TBIGridEditor OnChange = PageControl1Change object TabBIGrid: TTabSheet Caption = 'Options' - ExplicitLeft = 0 - ExplicitTop = 28 object Label1: TLabel Left = 16 Top = 200 @@ -101,6 +99,15 @@ object BIGridEditor: TBIGridEditor 'Yes' 'No') end + object CBColorize: TCheckBox + Left = 18 + Top = 262 + Width = 137 + Height = 17 + Caption = 'Colorize' + TabOrder = 5 + OnClick = CBColorizeClick + end end object TabPlugin: TTabSheet Caption = 'Plugin' diff --git a/src/delphi/VCL/BI.VCL.Editor.BIGrid.pas b/src/delphi/VCL/BI.VCL.Editor.BIGrid.pas index d3f1306..38785d4 100644 --- a/src/delphi/VCL/BI.VCL.Editor.BIGrid.pas +++ b/src/delphi/VCL/BI.VCL.Editor.BIGrid.pas @@ -20,6 +20,7 @@ TBIGridEditor = class(TForm) TabPlugin: TTabSheet; Label1: TLabel; CBShowItems: TComboBox; + CBColorize: TCheckBox; procedure BAltColorClick(Sender: TObject); procedure CBAltRowsClick(Sender: TObject); procedure CBFilterClick(Sender: TObject); @@ -28,6 +29,7 @@ TBIGridEditor = class(TForm) procedure PageControl1Change(Sender: TObject); procedure FormShow(Sender: TObject); procedure CBShowItemsChange(Sender: TObject); + procedure CBColorizeClick(Sender: TObject); private { Private declarations } diff --git a/src/delphi/VCL/BI.VCL.Editor.Chart.dfm b/src/delphi/VCL/BI.VCL.Editor.Chart.dfm index bddce8b..2fb3a1a 100644 --- a/src/delphi/VCL/BI.VCL.Editor.Chart.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.Chart.dfm @@ -27,6 +27,10 @@ object BIChartEditor: TBIChartEditor OnChange = PageControl1Change object TabOptions: TTabSheet Caption = 'Options' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object PageMode: TPageControl Left = 129 Top = 0 @@ -595,6 +599,10 @@ object BIChartEditor: TBIChartEditor object TabGeo: TTabSheet Caption = 'Geographic' ImageIndex = 3 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object CBFlags: TCheckBox Left = 16 Top = 134 @@ -751,6 +759,10 @@ object BIChartEditor: TBIChartEditor object TabData: TTabSheet Caption = 'Data' ImageIndex = 2 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object Panel1: TPanel Left = 0 Top = 0 diff --git a/src/delphi/VCL/BI.VCL.Editor.Data.dfm b/src/delphi/VCL/BI.VCL.Editor.Data.dfm index 7c48b1a..cc6c524 100644 --- a/src/delphi/VCL/BI.VCL.Editor.Data.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.Data.dfm @@ -21,7 +21,7 @@ object DataEditor: TDataEditor Top = 0 Width = 518 Height = 395 - ActivePage = TabFiles + ActivePage = TabDatabase Align = alClient TabOrder = 0 object TabFiles: TTabSheet @@ -35,7 +35,7 @@ object DataEditor: TDataEditor Top = 0 Width = 510 Height = 367 - ActivePage = TabFTP + ActivePage = TabFile Align = alClient TabOrder = 0 object TabFile: TTabSheet @@ -312,16 +312,12 @@ object DataEditor: TDataEditor object TabDatabase: TTabSheet Caption = 'Database' ImageIndex = 1 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object PageControlDBItems: TPageControl Left = 0 Top = 0 Width = 510 Height = 367 - ActivePage = TabConnection + ActivePage = SQL Align = alClient TabOrder = 0 object TabConnection: TTabSheet @@ -445,9 +441,10 @@ object DataEditor: TDataEditor Width = 502 Height = 54 Align = alBottom + ReadOnly = True + ScrollBars = ssVertical TabOrder = 7 Visible = False - WordWrap = False end object EDBPort: TEdit Left = 192 @@ -470,10 +467,6 @@ object DataEditor: TDataEditor object SQL: TTabSheet Caption = 'Items' ImageIndex = 1 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object PageControl3: TPageControl Left = 0 Top = 0 @@ -484,10 +477,6 @@ object DataEditor: TDataEditor TabOrder = 0 object TabItemAllDB: TTabSheet Caption = 'All' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 object LDBExclude: TLabel Left = 16 Top = 96 @@ -509,9 +498,9 @@ object DataEditor: TDataEditor object CBAllItems: TCheckBox Left = 16 Top = 16 - Width = 178 + Width = 101 Height = 17 - Caption = '&All Tables and Views' + Caption = '&All Items' Checked = True State = cbChecked TabOrder = 0 @@ -553,6 +542,15 @@ object DataEditor: TDataEditor TabOrder = 4 OnClick = CBDBSystemClick end + object CBDBViews: TCheckBox + Left = 200 + Top = 39 + Width = 137 + Height = 17 + Caption = 'Include &Views' + TabOrder = 5 + OnClick = CBDBViewsClick + end end object TabSQL: TTabSheet Caption = 'Custom SQL' @@ -576,6 +574,32 @@ object DataEditor: TDataEditor end end end + object TabDBOptions: TTabSheet + Caption = 'Options' + ImageIndex = 2 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 + object CBParallel: TCheckBox + Left = 16 + Top = 16 + Width = 153 + Height = 17 + Caption = 'Use multiple threads' + TabOrder = 0 + OnClick = CBParallelClick + end + object CBStats: TCheckBox + Left = 16 + Top = 48 + Width = 153 + Height = 17 + Caption = 'Precalculate Statistics' + TabOrder = 1 + OnClick = CBStatsClick + end + end end end object TabWeb: TTabSheet @@ -638,7 +662,7 @@ object DataEditor: TDataEditor TabOrder = 1 object TabHttpServer: TTabSheet Caption = 'Server' - ExplicitLeft = 8 + ExplicitLeft = 0 ExplicitTop = 0 ExplicitWidth = 0 ExplicitHeight = 0 @@ -855,9 +879,10 @@ object DataEditor: TDataEditor Width = 225 Height = 161 Caption = '&Import Style:' + ItemIndex = 0 Items.Strings = ( - 'Database Server' 'Files, Folders or URL' + 'Database Server' 'BI Web Server') TabOrder = 0 Visible = False diff --git a/src/delphi/VCL/BI.VCL.Editor.Data.pas b/src/delphi/VCL/BI.VCL.Editor.Data.pas index b6705a4..ec6ea5f 100644 --- a/src/delphi/VCL/BI.VCL.Editor.Data.pas +++ b/src/delphi/VCL/BI.VCL.Editor.Data.pas @@ -120,6 +120,10 @@ TDataEditor = class(TForm) ETimeout: TEdit; UDTimeout: TUpDown; Label23: TLabel; + TabDBOptions: TTabSheet; + CBParallel: TCheckBox; + CBStats: TCheckBox; + CBDBViews: TCheckBox; procedure FormDestroy(Sender: TObject); procedure EFileChange(Sender: TObject); procedure Button3Click(Sender: TObject); @@ -167,6 +171,9 @@ TDataEditor = class(TForm) procedure RGKindClick(Sender: TObject); procedure BOKClick(Sender: TObject); procedure ETimeoutChange(Sender: TObject); + procedure CBParallelClick(Sender: TObject); + procedure CBStatsClick(Sender: TObject); + procedure CBDBViewsClick(Sender: TObject); private { Private declarations } FOnChangeWeb : TNotifyEvent; @@ -178,6 +185,7 @@ TDataEditor = class(TForm) procedure DatabaseSettings; function DBDriverID:String; + procedure DoTest; procedure EnableTestButton; procedure FileSettings; function FileTypeExtension(const Index:Integer):String; diff --git a/src/delphi/VCL/BI.VCL.Editor.DataComponent.pas b/src/delphi/VCL/BI.VCL.Editor.DataComponent.pas index 09a4bc1..da8858a 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DataComponent.pas +++ b/src/delphi/VCL/BI.VCL.Editor.DataComponent.pas @@ -18,7 +18,13 @@ interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, + + {$IFDEF FPC} + BI.FPC, FGL, + {$ELSE} System.Generics.Collections, + {$ENDIF} + Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls, Vcl.StdCtrls, Vcl.Grids, BI.Data, Vcl.Menus; @@ -39,9 +45,7 @@ TDataComponent = class(TForm) private { Private declarations } - IComponents : TList; - - //Dummy : TComponent; + IComponents : {$IFDEF FPC}TFPGList{$ELSE}TList{$ENDIF}; FOnFilter : TFilterEvent; FOnSelected : TNotifyEvent; diff --git a/src/delphi/VCL/BI.VCL.Editor.DataSelect.dfm b/src/delphi/VCL/BI.VCL.Editor.DataSelect.dfm index 7782f87..fa8c4d3 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DataSelect.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.DataSelect.dfm @@ -22,10 +22,8 @@ object DataSelectEditor: TDataSelectEditor ActivePage = TabItems Align = alClient TabOrder = 0 - ExplicitHeight = 322 object TabItems: TTabSheet Caption = 'Items' - ExplicitHeight = 294 object Panel2: TPanel Left = 0 Top = 41 @@ -85,7 +83,6 @@ object DataSelectEditor: TDataSelectEditor OnClick = LItemsClick OnDragDrop = LItemsDragDrop OnDragOver = LItemsDragOver - ExplicitHeight = 134 end object Panel1: TPanel Left = 0 @@ -128,7 +125,6 @@ object DataSelectEditor: TDataSelectEditor Align = alBottom BevelOuter = bvNone TabOrder = 3 - ExplicitTop = 212 object Label2: TLabel Left = 12 Top = 6 @@ -180,7 +176,6 @@ object DataSelectEditor: TDataSelectEditor object TabSort: TTabSheet Caption = 'Sort By' ImageIndex = 1 - ExplicitHeight = 294 object LBSort: TCheckListBox Left = 0 Top = 41 @@ -193,7 +188,6 @@ object DataSelectEditor: TDataSelectEditor OnClick = LBSortClick OnDragDrop = LBSortDragDrop OnDragOver = LBSortDragOver - ExplicitHeight = 119 end object Panel3: TPanel Left = 0 @@ -249,7 +243,6 @@ object DataSelectEditor: TDataSelectEditor Align = alBottom BevelOuter = bvNone TabOrder = 2 - ExplicitTop = 160 object LSortError: TLabel Left = 12 Top = 112 @@ -306,7 +299,6 @@ object DataSelectEditor: TDataSelectEditor object TabFilter: TTabSheet Caption = 'Filter' ImageIndex = 2 - ExplicitHeight = 294 object LFilter: TLabel Left = 12 Top = 56 @@ -331,7 +323,6 @@ object DataSelectEditor: TDataSelectEditor object TabSQL: TTabSheet Caption = 'SQL' ImageIndex = 3 - ExplicitHeight = 294 object MemoSQL: TMemo Left = 0 Top = 0 @@ -340,7 +331,6 @@ object DataSelectEditor: TDataSelectEditor Align = alClient ReadOnly = True TabOrder = 0 - ExplicitHeight = 294 end end end @@ -353,8 +343,6 @@ object DataSelectEditor: TDataSelectEditor BevelOuter = bvNone TabOrder = 1 Visible = False - ExplicitTop = 317 - ExplicitWidth = 309 object Panel9: TPanel Left = 141 Top = 0 @@ -363,7 +351,6 @@ object DataSelectEditor: TDataSelectEditor Align = alRight BevelOuter = bvNone TabOrder = 0 - ExplicitLeft = 124 object BOK: TButton Left = 9 Top = 6 diff --git a/src/delphi/VCL/BI.VCL.Editor.DataSet.dfm b/src/delphi/VCL/BI.VCL.Editor.DataSet.dfm index 27d5515..3744370 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DataSet.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.DataSet.dfm @@ -24,8 +24,6 @@ object BIDataSetEditor: TBIDataSetEditor Align = alBottom BevelOuter = bvNone TabOrder = 0 - ExplicitTop = 409 - ExplicitWidth = 522 object CBPreview: TCheckBox Left = 16 Top = 12 @@ -43,7 +41,6 @@ object BIDataSetEditor: TBIDataSetEditor Align = alRight BevelOuter = bvNone TabOrder = 1 - ExplicitLeft = 337 object BOK: TButton Left = 13 Top = 8 @@ -86,15 +83,8 @@ object BIDataSetEditor: TBIDataSetEditor Align = alClient TabOrder = 1 OnChange = PageControl1Change - ExplicitTop = 56 - ExplicitWidth = 522 - ExplicitHeight = 347 object TabOptions: TTabSheet Caption = 'Options' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 514 - ExplicitHeight = 319 object Panel3: TPanel Left = 0 Top = 0 @@ -103,7 +93,6 @@ object BIDataSetEditor: TBIDataSetEditor Align = alTop BevelOuter = bvNone TabOrder = 0 - ExplicitWidth = 514 object Label1: TLabel Left = 3 Top = 63 @@ -140,19 +129,11 @@ object BIDataSetEditor: TBIDataSetEditor ParentBackground = False ParentColor = False TabOrder = 1 - ExplicitLeft = 56 - ExplicitTop = 32 - ExplicitWidth = 400 - ExplicitHeight = 250 end end object TabData: TTabSheet Caption = 'Data' ImageIndex = 1 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 514 - ExplicitHeight = 319 end end object Backup: TBIDataset diff --git a/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.dfm b/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.dfm index 5dd6540..9631eb3 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.dfm @@ -26,196 +26,231 @@ object DateTimeRangeEditor: TDateTimeRangeEditor OnChange = PageControl1Change object TabRange: TTabSheet Caption = 'Range' - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - object Label1: TLabel - Left = 6 - Top = 6 - Width = 28 - Height = 13 - Caption = 'From:' - end - object Label2: TLabel - Left = 6 - Top = 50 - Width = 16 - Height = 13 - Caption = 'To:' - end - object CBDay: TComboBox - Left = 6 - Top = 23 - Width = 51 - Height = 21 - Style = csDropDownList - DropDownCount = 31 + object PageRange: TPageControl + Left = 0 + Top = 0 + Width = 441 + Height = 232 + ActivePage = TabCalendar + Align = alClient TabOrder = 0 - OnChange = CBDayChange - end - object CBMonth: TComboBox - Left = 75 - Top = 23 - Width = 110 - Height = 21 - Style = csDropDownList - DropDownCount = 13 - TabOrder = 1 - OnChange = CBMonthChange - end - object CBYear: TComboBox - Left = 203 - Top = 23 - Width = 70 - Height = 21 - Style = csDropDownList - DropDownCount = 13 - TabOrder = 2 - OnChange = CBYearChange - end - object CBDayTo: TComboBox - Left = 6 - Top = 66 - Width = 51 - Height = 21 - Style = csDropDownList - DropDownCount = 31 - TabOrder = 3 - OnChange = CBDayToChange - end - object CBMonthTo: TComboBox - Left = 75 - Top = 66 - Width = 110 - Height = 21 - Style = csDropDownList - DropDownCount = 13 - TabOrder = 4 - OnChange = CBMonthToChange - end - object CBYearTo: TComboBox - Left = 203 - Top = 66 - Width = 70 - Height = 21 - Style = csDropDownList - DropDownCount = 13 - TabOrder = 5 - OnChange = CBYearToChange - end - object CBPeriod: TComboBox - Left = 6 - Top = 104 - Width = 115 - Height = 21 - Style = csDropDownList - TabOrder = 6 - OnChange = CBPeriodChange - Items.Strings = ( - 'All time' - 'Custom' - 'Today' - 'Yesterday' - 'This' - 'Last' - 'Next') - end - object CBPeriod2: TComboBox - Left = 134 - Top = 104 - Width = 115 - Height = 21 - Style = csDropDownList - Enabled = False - TabOrder = 7 - OnChange = CBPeriod2Change - Items.Strings = ( - 'Week' - 'Month' - 'Quarter' - 'Year') + OnChange = PageRangeChange + object TabCombo: TTabSheet + Caption = 'Period' + object Label1: TLabel + Left = 6 + Top = 6 + Width = 28 + Height = 13 + Caption = 'From:' + end + object Label2: TLabel + Left = 6 + Top = 50 + Width = 16 + Height = 13 + Caption = 'To:' + end + object CBDay: TComboBox + Left = 6 + Top = 23 + Width = 46 + Height = 21 + Style = csDropDownList + DropDownCount = 31 + TabOrder = 0 + OnChange = CBDayChange + end + object CBMonth: TComboBox + Left = 62 + Top = 23 + Width = 106 + Height = 21 + Style = csDropDownList + DropDownCount = 13 + TabOrder = 1 + OnChange = CBMonthChange + end + object CBYear: TComboBox + Left = 179 + Top = 23 + Width = 70 + Height = 21 + Style = csDropDownList + DropDownCount = 13 + TabOrder = 2 + OnChange = CBYearChange + end + object CBDayTo: TComboBox + Left = 6 + Top = 66 + Width = 46 + Height = 21 + Style = csDropDownList + DropDownCount = 31 + TabOrder = 3 + OnChange = CBDayToChange + end + object CBMonthTo: TComboBox + Left = 62 + Top = 66 + Width = 106 + Height = 21 + Style = csDropDownList + DropDownCount = 13 + TabOrder = 4 + OnChange = CBMonthToChange + end + object CBYearTo: TComboBox + Left = 179 + Top = 66 + Width = 70 + Height = 21 + Style = csDropDownList + DropDownCount = 13 + TabOrder = 5 + OnChange = CBYearToChange + end + object CBPeriod: TComboBox + Left = 6 + Top = 104 + Width = 115 + Height = 21 + Style = csDropDownList + TabOrder = 6 + OnChange = CBPeriodChange + Items.Strings = ( + 'All time' + 'Custom' + 'Today' + 'Yesterday' + 'This' + 'Last' + 'Next') + end + object CBPeriod2: TComboBox + Left = 134 + Top = 104 + Width = 115 + Height = 21 + Style = csDropDownList + Enabled = False + TabOrder = 7 + OnChange = CBPeriod2Change + Items.Strings = ( + 'Week' + 'Month' + 'Quarter' + 'Year') + end + end + object TabCalendar: TTabSheet + Caption = 'Calendar' + ImageIndex = 1 + object Label3: TLabel + Left = 5 + Top = 3 + Width = 28 + Height = 13 + Caption = '&From:' + FocusControl = CalendarFrom + end + object Label4: TLabel + Left = 192 + Top = 3 + Width = 16 + Height = 13 + Caption = '&To:' + FocusControl = CalendarTo + end + object CalendarFrom: TMonthCalendar + Left = 3 + Top = 20 + Width = 170 + Height = 143 + Date = 42509.702132650460000000 + ShowToday = False + ShowTodayCircle = False + TabOrder = 0 + OnClick = CalendarFromClick + end + object CalendarTo: TMonthCalendar + Left = 192 + Top = 20 + Width = 169 + Height = 143 + Date = 42509.702132650460000000 + ShowToday = False + ShowTodayCircle = False + TabOrder = 1 + OnClick = CalendarFromClick + end + end + object TabFromTo: TTabSheet + Caption = 'From / To' + ImageIndex = 2 + end end end - object TabCalendar: TTabSheet - Caption = 'Calendar' - ImageIndex = 1 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - object Label3: TLabel - Left = 5 - Top = 3 - Width = 28 - Height = 13 - Caption = '&From:' - FocusControl = CalendarFrom - end - object Label4: TLabel - Left = 192 - Top = 3 - Width = 16 - Height = 13 - Caption = '&To:' - FocusControl = CalendarTo - end - object CalendarFrom: TMonthCalendar - Left = 3 - Top = 20 - Width = 170 - Height = 143 - Date = 42509.774247106480000000 - ShowToday = False - ShowTodayCircle = False + object TabSelected: TTabSheet + Caption = 'Selected' + ImageIndex = 2 + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 441 + Height = 41 + Align = alTop + BevelOuter = bvNone TabOrder = 0 - OnClick = CalendarFromClick - end - object CalendarTo: TMonthCalendar - Left = 192 - Top = 20 - Width = 169 - Height = 143 - Date = 42509.774247106480000000 - ShowToday = False - ShowTodayCircle = False - TabOrder = 1 - OnClick = CalendarFromClick + object Label5: TLabel + Left = 6 + Top = 12 + Width = 24 + Height = 13 + Caption = '&Part:' + FocusControl = CBPart + end + object CBPart: TComboBox + Left = 64 + Top = 8 + Width = 161 + Height = 21 + Style = csDropDownList + TabOrder = 0 + OnChange = CBPartChange + end end end object TabSheet3: TTabSheet - Caption = 'Selected' + Caption = 'Included' ImageIndex = 2 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 + object Splitter1: TSplitter + Left = 153 + Top = 0 + Height = 232 + ExplicitLeft = 216 + ExplicitTop = 64 + ExplicitHeight = 100 + end object PanelMonths: TPanel Left = 0 Top = 0 - Width = 185 + Width = 153 Height = 232 Align = alLeft BevelOuter = bvNone TabOrder = 0 end object PanelWeeks: TPanel - Left = 185 + Left = 156 Top = 0 - Width = 185 + Width = 285 Height = 232 - Align = alLeft + Align = alClient BevelOuter = bvNone TabOrder = 1 end end - object TabFromTo: TTabSheet - Caption = 'From / To' - ImageIndex = 3 - ExplicitLeft = 0 - ExplicitTop = 0 - ExplicitWidth = 0 - ExplicitHeight = 0 - end end end diff --git a/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.pas b/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.pas index 9dcfa6d..1d83aa9 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.pas +++ b/src/delphi/VCL/BI.VCL.Editor.DateTimeRange.pas @@ -5,32 +5,56 @@ interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, + + {$IFDEF FPC} + Calendar, + {$ENDIF} + BI.Data, Vcl.ComCtrls, BI.VCL.Editor.ListItems, Vcl.ExtCtrls, BI.Expression, BI.VCL.Editor.NumericFromTo, BI.Arrays; type + TSelectedPart=record + public + Enabled : Boolean; + Part : TDateTimePart; + Value : Integer; + DateTime : TDateTime; + end; + + {$IFDEF FPC} + TMonthCalendar=TCalendar; + {$ENDIF} + TDateTimeRangeEditor = class(TForm) PageControl1: TPageControl; TabRange: TTabSheet; - TabCalendar: TTabSheet; TabSheet3: TTabSheet; + PanelMonths: TPanel; + PanelWeeks: TPanel; + Splitter1: TSplitter; + PageRange: TPageControl; + TabCombo: TTabSheet; Label1: TLabel; + Label2: TLabel; CBDay: TComboBox; CBMonth: TComboBox; CBYear: TComboBox; - Label2: TLabel; CBDayTo: TComboBox; CBMonthTo: TComboBox; CBYearTo: TComboBox; CBPeriod: TComboBox; CBPeriod2: TComboBox; - CalendarFrom: TMonthCalendar; - CalendarTo: TMonthCalendar; + TabCalendar: TTabSheet; Label3: TLabel; Label4: TLabel; - PanelMonths: TPanel; - PanelWeeks: TPanel; + CalendarFrom: TMonthCalendar; + CalendarTo: TMonthCalendar; TabFromTo: TTabSheet; + TabSelected: TTabSheet; + Panel1: TPanel; + Label5: TLabel; + CBPart: TComboBox; procedure CBYearChange(Sender: TObject); procedure CBMonthChange(Sender: TObject); procedure CBYearToChange(Sender: TObject); @@ -43,6 +67,8 @@ TDateTimeRangeEditor = class(TForm) procedure CBDayChange(Sender: TObject); procedure CBDayToChange(Sender: TObject); procedure PageControl1Change(Sender: TObject); + procedure PageRangeChange(Sender: TObject); + procedure CBPartChange(Sender: TObject); private { Private declarations } @@ -50,30 +76,36 @@ TDateTimeRangeEditor = class(TForm) FOnChanged : TNotifyEvent; - IFromTo : TNumericFromTo; + IDatePart : TDateTimePart; + + IFromTo, + ISelected : TNumericFromTo; IMonths, IWeeks : TFormListItems; procedure ChangedFromTo(Sender: TObject); + procedure ChangedIncluded(Sender: TObject); procedure ChangedSelected(Sender: TObject); function DateFrom(const AYear,AMonth,ADay:TComboBox):TDateTime; procedure DoAddDays(const AYear,AMonth,ADay:TComboBox; First:Boolean); procedure DoAddMonths(const AYear,AMonth:TComboBox; First:Boolean); procedure Modified; procedure SelectCombos(const AFrom,ATo:TDateTime); + function SelectedPart:TDateTimePart; procedure SetCustom; public { Public declarations } Data : TDataItem; - function Filter:TLogicalExpression; + //function Filter:TLogicalExpression; function FromDate:TDateTime; function ToDate:TDateTime; function Months:TBooleanArray; + function Part:TSelectedPart; function WeekDays:TBooleanArray; procedure Refresh(const AData:TDataItem); diff --git a/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.dfm b/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.dfm index ded8103..c4a29b5 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.dfm @@ -125,6 +125,10 @@ object DynamicFilterEditor: TDynamicFilterEditor TabOrder = 2 object TabData: TTabSheet Caption = 'Data' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object BITree1: TBITree Left = 0 Top = 41 @@ -160,6 +164,10 @@ object DynamicFilterEditor: TDynamicFilterEditor object TabItems: TTabSheet Caption = 'Items' ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object Splitter1: TSplitter Left = 0 Top = 264 @@ -180,7 +188,6 @@ object DynamicFilterEditor: TDynamicFilterEditor ItemHeight = 13 TabOrder = 0 OnClick = CBItemsClick - ExplicitHeight = 226 end object Panel3: TPanel Left = 0 @@ -192,29 +199,47 @@ object DynamicFilterEditor: TDynamicFilterEditor TabOrder = 1 object CBEnabled: TCheckBox Left = 5 - Top = 8 + Top = 11 Width = 97 Height = 17 Caption = '&Enabled' TabOrder = 0 OnClick = CBEnabledClick end + object BDelete: TButton + Left = 120 + Top = 9 + Width = 75 + Height = 25 + Caption = 'Delete' + Enabled = False + TabOrder = 1 + OnClick = BDeleteClick + end end object PageItem: TPageControl Left = 0 Top = 267 Width = 410 Height = 230 - ActivePage = TabDateTime + ActivePage = TabNumeric Align = alBottom TabOrder = 2 Visible = False object TabDateTime: TTabSheet Caption = 'Date Time' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end object TabBoolean: TTabSheet Caption = 'Boolean' ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object CBTrue: TCheckBox Left = 16 Top = 16 @@ -237,10 +262,42 @@ object DynamicFilterEditor: TDynamicFilterEditor object TabNumeric: TTabSheet Caption = 'Numeric' ImageIndex = 2 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 + object PageNumeric: TPageControl + Left = 0 + Top = 0 + Width = 402 + Height = 202 + ActivePage = TabNumericRange + Align = alClient + TabOrder = 0 + object TabNumericRange: TTabSheet + Caption = 'Range' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 + end + object TabNumericSelected: TTabSheet + Caption = 'Selected' + ImageIndex = 1 + ExplicitLeft = 1 + ExplicitTop = 30 + ExplicitWidth = 0 + ExplicitHeight = 0 + end + end end object TabText: TTabSheet Caption = 'Text' ImageIndex = 3 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object PageControl2: TPageControl Left = 0 Top = 0 @@ -251,10 +308,18 @@ object DynamicFilterEditor: TDynamicFilterEditor TabOrder = 0 object TabIncluded: TTabSheet Caption = 'Include' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end object TabExcluded: TTabSheet Caption = 'Exclude' ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end end end diff --git a/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.pas b/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.pas index 7b6f080..757ca33 100644 --- a/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.pas +++ b/src/delphi/VCL/BI.VCL.Editor.DynamicFilter.pas @@ -89,6 +89,10 @@ TDynamicFilterEditor = class(TForm) TabIncluded: TTabSheet; TabExcluded: TTabSheet; Splitter1: TSplitter; + BDelete: TButton; + PageNumeric: TPageControl; + TabNumericRange: TTabSheet; + TabNumericSelected: TTabSheet; procedure FormCreate(Sender: TObject); procedure ECustomChange(Sender: TObject); procedure FormDestroy(Sender: TObject); @@ -102,6 +106,7 @@ TDynamicFilterEditor = class(TForm) procedure CBItemsClickCheck(Sender: TObject); procedure CBEnabledClick(Sender: TObject); procedure BAddClick(Sender: TObject); + procedure BDeleteClick(Sender: TObject); private { Private declarations } @@ -116,7 +121,9 @@ TDynamicFilterEditor = class(TForm) IData, IMainData : TDataItem; - INumericFromTo : TNumericFromTo; + INumericFromTo, + INumericSelected : TNumericFromTo; + ITextInclude, ITextExclude : TSelectTextItems; IDateTimeRange : TDateTimeRangeEditor; diff --git a/src/delphi/VCL/BI.VCL.Editor.Expression.pas b/src/delphi/VCL/BI.VCL.Editor.Expression.pas index a4ee3e6..f6309f7 100644 --- a/src/delphi/VCL/BI.VCL.Editor.Expression.pas +++ b/src/delphi/VCL/BI.VCL.Editor.Expression.pas @@ -1,3 +1,9 @@ +{*********************************************} +{ TeeBI Software Library } +{ Expression Editor } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} unit BI.VCL.Editor.Expression; interface diff --git a/src/delphi/VCL/BI.VCL.Editor.ListItems.dfm b/src/delphi/VCL/BI.VCL.Editor.ListItems.dfm index f30bc0c..3e74250 100644 --- a/src/delphi/VCL/BI.VCL.Editor.ListItems.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.ListItems.dfm @@ -35,7 +35,6 @@ object FormListItems: TFormListItems Align = alTop BevelOuter = bvNone TabOrder = 1 - OnResize = Panel1Resize object SBUp: TSpeedButton Left = 5 Top = 4 diff --git a/src/delphi/VCL/BI.VCL.Editor.ListItems.pas b/src/delphi/VCL/BI.VCL.Editor.ListItems.pas index 6cc44ea..88949e6 100644 --- a/src/delphi/VCL/BI.VCL.Editor.ListItems.pas +++ b/src/delphi/VCL/BI.VCL.Editor.ListItems.pas @@ -28,7 +28,6 @@ TFormListItems = class(TForm) procedure SBUpClick(Sender: TObject); procedure BAllClick(Sender: TObject); procedure BNoneClick(Sender: TObject); - procedure Panel1Resize(Sender: TObject); private { Private declarations } diff --git a/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.dfm b/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.dfm index 223fb7c..27995e5 100644 --- a/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.dfm @@ -58,7 +58,7 @@ object NumericFromTo: TNumericFromTo OnChange = TBFromChange end object TBTo: TTrackBar - Left = 6 + Left = 0 Top = 78 Width = 373 Height = 30 diff --git a/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.pas b/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.pas index acc4f4e..aab2eb3 100644 --- a/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.pas +++ b/src/delphi/VCL/BI.VCL.Editor.NumericFromTo.pas @@ -48,6 +48,8 @@ TNumericFromTo = class(TForm) procedure SetTo(const Value: Extended); function TrySetTrack(const S:String; const ATrack:TTrackBar):Boolean; function ValueOf(const APosition:Integer):Extended; + protected + procedure HideTo; public { Public declarations } diff --git a/src/delphi/VCL/BI.VCL.Editor.Query.dfm b/src/delphi/VCL/BI.VCL.Editor.Query.dfm index fb1ba33..28d46a9 100644 --- a/src/delphi/VCL/BI.VCL.Editor.Query.dfm +++ b/src/delphi/VCL/BI.VCL.Editor.Query.dfm @@ -44,6 +44,10 @@ object BIQueryEditor: TBIQueryEditor OnChange = PageDataChange object TabData: TTabSheet Caption = 'Data' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end object TabFilter: TTabSheet Caption = 'Filter' @@ -436,6 +440,10 @@ object BIQueryEditor: TBIQueryEditor Visible = False object TabItem: TTabSheet Caption = 'Options' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object Label3: TLabel Left = 9 Top = 4 @@ -499,6 +507,10 @@ object BIQueryEditor: TBIQueryEditor object TabMeasureOptions: TTabSheet Caption = 'Options' ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object PageMeasures: TPageControl Left = 0 Top = 0 @@ -509,6 +521,10 @@ object BIQueryEditor: TBIQueryEditor TabOrder = 0 object TabMeasure: TTabSheet Caption = 'Aggregate' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object CBAggregate: TComboBox Left = 8 Top = 14 @@ -539,6 +555,10 @@ object BIQueryEditor: TBIQueryEditor object TabCalc: TTabSheet Caption = 'Calculation' ImageIndex = 3 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object RGRunning: TRadioGroup Left = 135 Top = 3 @@ -583,6 +603,10 @@ object BIQueryEditor: TBIQueryEditor object TabItemData: TTabSheet Caption = 'Data' ImageIndex = 2 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object SpeedButton1: TSpeedButton Left = 231 Top = 22 @@ -647,6 +671,10 @@ object BIQueryEditor: TBIQueryEditor OnChange = PagePreviewChange object TabGrid: TTabSheet Caption = 'Grid' + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object BIGrid1: TBIGrid Left = 0 Top = 0 @@ -662,10 +690,18 @@ object BIQueryEditor: TBIQueryEditor object TabChart: TTabSheet Caption = 'Chart' ImageIndex = 1 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 end object TabSQL: TTabSheet Caption = 'SQL' ImageIndex = 2 + ExplicitLeft = 0 + ExplicitTop = 0 + ExplicitWidth = 0 + ExplicitHeight = 0 object MemoSQL: TMemo Left = 0 Top = 0 diff --git a/src/delphi/VCL/BI.VCL.Editor.Query.pas b/src/delphi/VCL/BI.VCL.Editor.Query.pas index c1100eb..a4eede1 100644 --- a/src/delphi/VCL/BI.VCL.Editor.Query.pas +++ b/src/delphi/VCL/BI.VCL.Editor.Query.pas @@ -230,6 +230,7 @@ TBIQueryEditor = class(TForm) procedure SortChanged(Sender:TObject); procedure TryAddMasters(const AProc:TAddMasterProc); procedure TryShowPreviewGrid; + procedure TryShowSQL; public { Public declarations } diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.Data.dfm b/src/delphi/VCL/BI.VCL.Editor.Template.Data.dfm new file mode 100644 index 0000000..ca343e8 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.Data.dfm @@ -0,0 +1,86 @@ +object DataGallery: TDataGallery + Left = 0 + Top = 0 + Caption = 'Template Data Gallery' + ClientHeight = 547 + ClientWidth = 650 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Splitter1: TSplitter + Left = 233 + Top = 0 + Height = 506 + ExplicitLeft = 336 + ExplicitTop = 240 + ExplicitHeight = 100 + end + object Panel1: TPanel + Left = 0 + Top = 506 + Width = 650 + Height = 41 + Align = alBottom + BevelOuter = bvNone + TabOrder = 0 + object Panel2: TPanel + Left = 465 + Top = 0 + Width = 185 + Height = 41 + Align = alRight + BevelOuter = bvNone + TabOrder = 0 + object BOK: TButton + Left = 0 + Top = 8 + Width = 75 + Height = 25 + Caption = 'OK' + Enabled = False + ModalResult = 1 + TabOrder = 0 + end + object BCancel: TButton + Left = 96 + Top = 8 + Width = 75 + Height = 25 + Cancel = True + Caption = 'Cancel' + Default = True + ModalResult = 2 + TabOrder = 1 + end + end + end + object LBData: TListBox + Left = 0 + Top = 0 + Width = 233 + Height = 506 + Align = alLeft + ItemHeight = 13 + TabOrder = 1 + OnClick = LBDataClick + end + object BIGrid1: TBIGrid + Left = 236 + Top = 0 + Width = 414 + Height = 506 + Align = alClient + UseDockManager = False + ParentBackground = False + ParentColor = False + TabOrder = 2 + ExplicitLeft = 233 + ExplicitWidth = 417 + end +end diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.Data.pas b/src/delphi/VCL/BI.VCL.Editor.Template.Data.pas new file mode 100644 index 0000000..5c78061 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.Data.pas @@ -0,0 +1,44 @@ +{*********************************************} +{ TeeBI Software Library } +{ TVisualData Dashboard Editor } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.VCL.Editor.Template.Data; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, + BI.Dashboard, BI.VCL.DataControl, BI.VCL.Grid; + +type + TDataGallery = class(TForm) + Panel1: TPanel; + Panel2: TPanel; + BOK: TButton; + BCancel: TButton; + LBData: TListBox; + BIGrid1: TBIGrid; + Splitter1: TSplitter; + procedure LBDataClick(Sender: TObject); + private + { Private declarations } + + FData : TVisualDataItems; + public + { Public declarations } + + class procedure AddData(const AItems:TStrings; const AData:TVisualDataItems); static; + + function Current:TVisualData; + + class function Choose(const AOwner:TComponent; + const ADataItems:TVisualDataItems; + out AData:TVisualData):Boolean; static; + + procedure Refresh(const ADataItems:TVisualDataItems); + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.Layouts.dfm b/src/delphi/VCL/BI.VCL.Editor.Template.Layouts.dfm new file mode 100644 index 0000000..e07ef13 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.Layouts.dfm @@ -0,0 +1,123 @@ +object LayoutGallery: TLayoutGallery + Left = 0 + Top = 0 + Caption = 'Template Layout Gallery' + ClientHeight = 591 + ClientWidth = 660 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object Splitter1: TSplitter + Left = 185 + Top = 0 + Height = 550 + ExplicitLeft = 336 + ExplicitTop = 264 + ExplicitHeight = 100 + end + object Panel1: TPanel + Left = 0 + Top = 550 + Width = 660 + Height = 41 + Align = alBottom + BevelOuter = bvNone + TabOrder = 0 + object Panel2: TPanel + Left = 475 + Top = 0 + Width = 185 + Height = 41 + Align = alRight + BevelOuter = bvNone + TabOrder = 0 + object BOK: TButton + Left = 0 + Top = 8 + Width = 75 + Height = 25 + Caption = 'OK' + Enabled = False + ModalResult = 1 + TabOrder = 0 + end + object BCancel: TButton + Left = 96 + Top = 8 + Width = 75 + Height = 25 + Cancel = True + Caption = 'Cancel' + Default = True + ModalResult = 2 + TabOrder = 1 + end + end + object Button1: TButton + Left = 17 + Top = 6 + Width = 75 + Height = 25 + Caption = 'Design...' + TabOrder = 1 + OnClick = Button1Click + end + end + object BIVisual1: TBIVisual + Left = 188 + Top = 0 + Width = 472 + Height = 550 + Align = alClient + TabOrder = 1 + ExplicitLeft = 185 + ExplicitWidth = 475 + end + object Panel3: TPanel + Left = 0 + Top = 0 + Width = 185 + Height = 550 + Align = alLeft + BevelOuter = bvNone + TabOrder = 2 + ExplicitTop = -6 + object LBLayouts: TListBox + Left = 0 + Top = 41 + Width = 185 + Height = 509 + Align = alClient + ItemHeight = 13 + TabOrder = 0 + OnClick = LBLayoutsClick + end + object Panel4: TPanel + Left = 0 + Top = 0 + Width = 185 + Height = 41 + Align = alTop + BevelOuter = bvNone + TabOrder = 1 + ExplicitLeft = -6 + ExplicitTop = -6 + object CBCurrent: TCheckBox + Left = 17 + Top = 13 + Width = 97 + Height = 17 + Caption = '&Current' + TabOrder = 0 + OnClick = CBCurrentClick + end + end + end +end diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.Layouts.pas b/src/delphi/VCL/BI.VCL.Editor.Template.Layouts.pas new file mode 100644 index 0000000..d2e3a9a --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.Layouts.pas @@ -0,0 +1,50 @@ +{*********************************************} +{ TeeBI Software Library } +{ TLayouts Dashboard Editor } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.VCL.Editor.Template.Layouts; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, + + BI.VCL.Dashboard, BI.Dashboard.Layouts; + +type + TLayoutGallery = class(TForm) + Panel1: TPanel; + Panel2: TPanel; + BOK: TButton; + BCancel: TButton; + BIVisual1: TBIVisual; + Panel3: TPanel; + LBLayouts: TListBox; + Panel4: TPanel; + CBCurrent: TCheckBox; + Splitter1: TSplitter; + Button1: TButton; + procedure LBLayoutsClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure CBCurrentClick(Sender: TObject); + procedure Button1Click(Sender: TObject); + private + { Private declarations } + + ICurrent : TLayoutItem; + + procedure AddList(const ALayouts:TLayouts); + procedure Preview(const ALayout:TLayoutItem); + function Selected:TLayoutItem; + public + { Public declarations } + + class function Choose(const AOwner:TComponent; + out ALayout:String; + const ACurrent:TLayoutItem):Boolean; static; + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.Panels.dfm b/src/delphi/VCL/BI.VCL.Editor.Template.Panels.dfm new file mode 100644 index 0000000..15eb3a0 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.Panels.dfm @@ -0,0 +1,83 @@ +object PanelGallery: TPanelGallery + Left = 0 + Top = 0 + Caption = 'Template Panels Gallery' + ClientHeight = 514 + ClientWidth = 717 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + PixelsPerInch = 96 + TextHeight = 13 + object Splitter1: TSplitter + Left = 145 + Top = 0 + Height = 473 + ExplicitLeft = 368 + ExplicitTop = 224 + ExplicitHeight = 100 + end + object Panel1: TPanel + Left = 0 + Top = 473 + Width = 717 + Height = 41 + Align = alBottom + BevelOuter = bvNone + TabOrder = 0 + object Panel2: TPanel + Left = 532 + Top = 0 + Width = 185 + Height = 41 + Align = alRight + BevelOuter = bvNone + TabOrder = 0 + object BOK: TButton + Left = 0 + Top = 8 + Width = 75 + Height = 25 + Caption = 'OK' + Enabled = False + ModalResult = 1 + TabOrder = 0 + end + object BCancel: TButton + Left = 96 + Top = 8 + Width = 75 + Height = 25 + Cancel = True + Caption = 'Cancel' + Default = True + ModalResult = 2 + TabOrder = 1 + end + end + end + object LBPanels: TListBox + Left = 0 + Top = 0 + Width = 145 + Height = 473 + Align = alLeft + ItemHeight = 13 + TabOrder = 1 + OnClick = LBPanelsClick + end + object BIVisual1: TBIVisual + Left = 148 + Top = 0 + Width = 569 + Height = 473 + Align = alClient + TabOrder = 2 + ExplicitLeft = 145 + ExplicitWidth = 572 + end +end diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.Panels.pas b/src/delphi/VCL/BI.VCL.Editor.Template.Panels.pas new file mode 100644 index 0000000..77d7358 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.Panels.pas @@ -0,0 +1,45 @@ +{*********************************************} +{ TeeBI Software Library } +{ TBIPanel Dashboard Editor } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.VCL.Editor.Template.Panels; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, BI.VCL.Dashboard, + Vcl.StdCtrls, + BI.Dashboard; + +type + TPanelGallery = class(TForm) + Panel1: TPanel; + LBPanels: TListBox; + BIVisual1: TBIVisual; + Panel2: TPanel; + BOK: TButton; + BCancel: TButton; + Splitter1: TSplitter; + procedure LBPanelsClick(Sender: TObject); + private + { Private declarations } + + FPanels : TPanels; + public + { Public declarations } + + class procedure AddPanels(const AItems:TStrings; const APanels:TPanels); static; + + function Current:TBIPanel; + + class function Choose(const AOwner:TComponent; + const APanels:TPanels; + out APanel:TBIPanel):Boolean; static; + + procedure Refresh(const APanels:TPanels); + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.dfm b/src/delphi/VCL/BI.VCL.Editor.Template.dfm new file mode 100644 index 0000000..8281191 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.dfm @@ -0,0 +1,499 @@ +object TemplateEditor: TTemplateEditor + Left = 0 + Top = 0 + Caption = 'Visual Editor' + ClientHeight = 624 + ClientWidth = 836 + Color = clBtnFace + Font.Charset = DEFAULT_CHARSET + Font.Color = clWindowText + Font.Height = -11 + Font.Name = 'Tahoma' + Font.Style = [] + OldCreateOrder = False + OnClose = FormClose + OnCreate = FormCreate + OnShow = FormShow + PixelsPerInch = 96 + TextHeight = 13 + object Splitter2: TSplitter + Left = 273 + Top = 0 + Height = 624 + ExplicitLeft = 424 + ExplicitTop = 280 + ExplicitHeight = 100 + end + object Panel1: TPanel + Left = 0 + Top = 0 + Width = 273 + Height = 624 + Align = alLeft + BevelOuter = bvNone + TabOrder = 0 + object Splitter1: TSplitter + Left = 0 + Top = 408 + Width = 273 + Height = 3 + Cursor = crVSplit + Align = alBottom + ExplicitTop = 0 + ExplicitWidth = 431 + end + object BITree1: TBITree + Left = 0 + Top = 41 + Width = 273 + Height = 367 + Align = alClient + UseDockManager = False + ParentBackground = False + ParentColor = False + PopupMenu = PopupItem + TabOrder = 0 + OnChange = BITree1Change + ExplicitLeft = 1 + ExplicitTop = 39 + ExplicitHeight = 387 + end + object PageProperties: TPageControl + Left = 0 + Top = 411 + Width = 273 + Height = 213 + ActivePage = TabItem + Align = alBottom + TabOrder = 1 + Visible = False + object TabData: TTabSheet + Caption = 'Data' + ExplicitHeight = 165 + object Label2: TLabel + Left = 7 + Top = 69 + Width = 27 + Height = 13 + Caption = '&Data:' + end + object LData: TLabel + Left = 41 + Top = 69 + Width = 3 + Height = 13 + end + object BChange: TButton + Left = 7 + Top = 90 + Width = 75 + Height = 25 + Caption = '&Change...' + Enabled = False + TabOrder = 0 + OnClick = BChangeClick + end + object BEditProvider: TButton + Left = 164 + Top = 30 + Width = 75 + Height = 25 + Caption = 'Edit...' + Enabled = False + TabOrder = 1 + OnClick = BEditProviderClick + end + end + object TabPanel: TTabSheet + Caption = 'Panel' + ImageIndex = 1 + ExplicitHeight = 165 + object Label3: TLabel + Left = 7 + Top = 60 + Width = 24 + Height = 13 + Caption = '&Kind:' + FocusControl = CBPanelKind + end + object Label7: TLabel + Left = 7 + Top = 8 + Width = 27 + Height = 13 + Caption = '&Data:' + FocusControl = CBPanelData + end + object CBPanelKind: TComboBox + Left = 7 + Top = 79 + Width = 145 + Height = 21 + Style = csDropDownList + TabOrder = 0 + OnChange = CBPanelKindChange + Items.Strings = ( + 'Automatic' + 'Buttons' + 'Chart' + 'Check Boxes' + 'Check Listbox' + 'Combo Box' + 'Grid' + 'Image' + 'List' + 'Navigator' + 'Radio Buttons' + 'Slider' + 'Text' + 'Tree') + end + object CBPanelData: TComboBox + Left = 7 + Top = 27 + Width = 145 + Height = 21 + Style = csDropDownList + TabOrder = 1 + OnChange = CBPanelDataChange + Items.Strings = ( + 'Undefined' + 'Grid' + 'List' + 'Text' + 'Check Listbox' + 'Combo Box' + 'Buttons' + 'Image' + 'Slider' + 'Check Boxes' + 'Navigator' + 'Tree' + 'Radio Buttons' + 'Chart') + end + end + object TabDashboard: TTabSheet + Caption = 'Dashboard' + ImageIndex = 2 + ExplicitHeight = 165 + object LLayout: TLabel + Left = 98 + Top = 85 + Width = 3 + Height = 13 + end + object CBSplitters: TCheckBox + Left = 9 + Top = 9 + Width = 97 + Height = 17 + Caption = '&Splitters' + TabOrder = 0 + OnClick = CBSplittersClick + end + object CBTitles: TCheckBox + Left = 9 + Top = 32 + Width = 97 + Height = 17 + Caption = '&Titles' + TabOrder = 1 + OnClick = CBTitlesClick + end + object BSelectLayout: TButton + Left = 9 + Top = 80 + Width = 75 + Height = 25 + Caption = '&Layout...' + TabOrder = 2 + OnClick = BSelectLayoutClick + end + end + object TabItem: TTabSheet + Caption = 'Item' + ImageIndex = 3 + ExplicitHeight = 165 + object PageControl2: TPageControl + Left = 0 + Top = 0 + Width = 265 + Height = 185 + ActivePage = TabItemOptions + Align = alClient + TabOrder = 0 + object TabItemOptions: TTabSheet + Caption = 'Options' + object Label4: TLabel + Left = 7 + Top = 9 + Width = 30 + Height = 13 + Caption = '&Panel:' + FocusControl = CBPanels + end + object Label5: TLabel + Left = 7 + Top = 56 + Width = 41 + Height = 13 + Caption = 'P&osition:' + FocusControl = CBPosition + end + object Label6: TLabel + Left = 7 + Top = 104 + Width = 24 + Height = 13 + Caption = '&Kind:' + FocusControl = CBItemKind + end + object LRealKind: TLabel + Left = 165 + Top = 126 + Width = 3 + Height = 13 + end + object CBPanels: TComboBox + Left = 7 + Top = 28 + Width = 145 + Height = 21 + Style = csDropDownList + TabOrder = 0 + OnChange = CBPanelsChange + end + object CBPosition: TComboBox + Left = 7 + Top = 75 + Width = 145 + Height = 21 + Style = csDropDownList + TabOrder = 1 + OnChange = CBPositionChange + end + object CBItemKind: TComboBox + Left = 7 + Top = 123 + Width = 145 + Height = 21 + Style = csDropDownList + TabOrder = 2 + OnChange = CBItemKindChange + Items.Strings = ( + 'Automatic' + 'Buttons' + 'Chart' + 'Check Boxes' + 'Check Listbox' + 'Combo Box' + 'Grid' + 'Image' + 'List' + 'Navigator' + 'Radio Buttons' + 'Slider' + 'Text' + 'Tree') + end + object CBAutoPosition: TCheckBox + Left = 165 + Top = 77 + Width = 84 + Height = 17 + Caption = 'Automatic' + TabOrder = 3 + OnClick = CBAutoPositionClick + end + end + object TabItemSize: TTabSheet + Caption = 'Size' + ImageIndex = 1 + object Label1: TLabel + Left = 16 + Top = 16 + Width = 32 + Height = 13 + Caption = '&Width:' + FocusControl = EWidth + end + object Label8: TLabel + Left = 16 + Top = 64 + Width = 35 + Height = 13 + Caption = '&Height:' + FocusControl = EHeight + end + object EWidth: TEdit + Left = 16 + Top = 32 + Width = 65 + Height = 21 + TabOrder = 0 + Text = '0' + end + object CBWidthUnits: TComboBox + Left = 92 + Top = 32 + Width = 73 + Height = 21 + Style = csDropDownList + ItemIndex = 0 + TabOrder = 1 + Text = 'Pixels' + Items.Strings = ( + 'Pixels' + 'Percent') + end + object EHeight: TEdit + Left = 16 + Top = 80 + Width = 65 + Height = 21 + TabOrder = 2 + Text = '0' + end + object CBHeightUnits: TComboBox + Left = 92 + Top = 80 + Width = 73 + Height = 21 + Style = csDropDownList + ItemIndex = 0 + TabOrder = 3 + Text = 'Pixels' + Items.Strings = ( + 'Pixels' + 'Percent') + end + end + end + end + end + object Panel2: TPanel + Left = 0 + Top = 0 + Width = 273 + Height = 41 + Align = alTop + BevelOuter = bvNone + TabOrder = 2 + object BDelete: TButton + Left = 155 + Top = 8 + Width = 75 + Height = 25 + Caption = 'Delete' + Enabled = False + TabOrder = 0 + OnClick = BDeleteClick + end + object BAdd: TButton + Left = 13 + Top = 8 + Width = 116 + Height = 25 + Caption = 'New Dashboard...' + TabOrder = 1 + OnClick = BAddClick + end + end + end + object PageControl1: TPageControl + Left = 276 + Top = 0 + Width = 560 + Height = 624 + ActivePage = TabPreview + Align = alClient + TabOrder = 1 + OnChange = PageControl1Change + object TabPreview: TTabSheet + Caption = 'Preview' + object BIGrid1: TBIGrid + Left = 0 + Top = 0 + Width = 552 + Height = 596 + Align = alClient + UseDockManager = False + ParentBackground = False + ParentColor = False + TabOrder = 0 + Visible = False + end + object BIVisual1: TBIVisual + Left = 0 + Top = 0 + Width = 552 + Height = 596 + Align = alClient + TabOrder = 1 + Dashboards = <> + Data = <> + Layouts = <> + Panels = <> + end + end + object TabTemplate: TTabSheet + Caption = 'Template' + ImageIndex = 1 + object MemoJSON: TMemo + Left = 0 + Top = 0 + Width = 552 + Height = 596 + Align = alClient + ScrollBars = ssBoth + TabOrder = 0 + WordWrap = False + end + end + end + object PopupData: TPopupMenu + Left = 72 + Top = 104 + object Data1: TMenuItem + Caption = '&From Store...' + OnClick = Data1Click + end + object Query1: TMenuItem + Caption = '&Query...' + OnClick = Query1Click + end + object Import1: TMenuItem + Caption = '&Import' + object Files1: TMenuItem + Caption = '&Files...' + OnClick = Files1Click + end + object DatabaseServer1: TMenuItem + Caption = '&Database Server...' + OnClick = DatabaseServer1Click + end + object BIWebServer1: TMenuItem + Caption = '&BIWeb Server...' + OnClick = BIWebServer1Click + end + end + end + object PopupItem: TPopupMenu + OnPopup = PopupItemPopup + Left = 72 + Top = 176 + object AddItem1: TMenuItem + Caption = '&Add Panel...' + OnClick = AddItem1Click + end + object RemoveItem1: TMenuItem + Caption = '&Remove' + OnClick = RemoveItem1Click + end + object Rename1: TMenuItem + Caption = 'Re&name' + OnClick = Rename1Click + end + end +end diff --git a/src/delphi/VCL/BI.VCL.Editor.Template.pas b/src/delphi/VCL/BI.VCL.Editor.Template.pas new file mode 100644 index 0000000..dd9c501 --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Editor.Template.pas @@ -0,0 +1,148 @@ +{*********************************************} +{ TeeBI Software Library } +{ TBITemplate Dashboard Editor } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.VCL.Editor.Template; + +interface + +uses + Winapi.Windows, Winapi.Messages, System.SysUtils, System.Classes, Vcl.Graphics, + Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.StdCtrls, + Vcl.ComCtrls, Vcl.Menus, + + BI.Data, BI.Persist, + BI.Dashboard, BI.VCL.Dashboard, BI.VCL.DataControl, BI.VCL.Grid, BI.VCL.Tree; + +type + TTemplateEditor = class(TForm) + Panel1: TPanel; + BIVisual1: TBIVisual; + BIGrid1: TBIGrid; + BITree1: TBITree; + PageProperties: TPageControl; + TabData: TTabSheet; + Splitter1: TSplitter; + Label2: TLabel; + LData: TLabel; + BChange: TButton; + Splitter2: TSplitter; + TabPanel: TTabSheet; + Label3: TLabel; + CBPanelKind: TComboBox; + TabDashboard: TTabSheet; + CBSplitters: TCheckBox; + CBTitles: TCheckBox; + TabItem: TTabSheet; + Label7: TLabel; + CBPanelData: TComboBox; + Panel2: TPanel; + BDelete: TButton; + PageControl1: TPageControl; + TabPreview: TTabSheet; + TabTemplate: TTabSheet; + MemoJSON: TMemo; + BEditProvider: TButton; + BAdd: TButton; + PopupData: TPopupMenu; + Data1: TMenuItem; + Query1: TMenuItem; + Import1: TMenuItem; + Files1: TMenuItem; + DatabaseServer1: TMenuItem; + BIWebServer1: TMenuItem; + PopupItem: TPopupMenu; + AddItem1: TMenuItem; + RemoveItem1: TMenuItem; + BSelectLayout: TButton; + LLayout: TLabel; + Rename1: TMenuItem; + PageControl2: TPageControl; + TabItemOptions: TTabSheet; + TabItemSize: TTabSheet; + Label4: TLabel; + Label5: TLabel; + Label6: TLabel; + CBPanels: TComboBox; + CBPosition: TComboBox; + CBItemKind: TComboBox; + CBAutoPosition: TCheckBox; + LRealKind: TLabel; + Label1: TLabel; + EWidth: TEdit; + CBWidthUnits: TComboBox; + Label8: TLabel; + EHeight: TEdit; + CBHeightUnits: TComboBox; + procedure FormCreate(Sender: TObject); + procedure BITree1Change(Sender: TObject); + procedure BChangeClick(Sender: TObject); + procedure CBDataKindChange(Sender: TObject); + procedure CBPanelKindChange(Sender: TObject); + procedure CBSplittersClick(Sender: TObject); + procedure CBTitlesClick(Sender: TObject); + procedure CBItemKindChange(Sender: TObject); + procedure CBPanelsChange(Sender: TObject); + procedure CBPositionChange(Sender: TObject); + procedure CBAutoPositionClick(Sender: TObject); + procedure CBPanelDataChange(Sender: TObject); + procedure BDeleteClick(Sender: TObject); + procedure PageControl1Change(Sender: TObject); + procedure BEditProviderClick(Sender: TObject); + procedure FormShow(Sender: TObject); + procedure FormClose(Sender: TObject; var Action: TCloseAction); + procedure BAddClick(Sender: TObject); + procedure Data1Click(Sender: TObject); + procedure PopupItemPopup(Sender: TObject); + procedure AddItem1Click(Sender: TObject); + procedure RemoveItem1Click(Sender: TObject); + procedure BSelectLayoutClick(Sender: TObject); + procedure Query1Click(Sender: TObject); + procedure Files1Click(Sender: TObject); + procedure DatabaseServer1Click(Sender: TObject); + procedure BIWebServer1Click(Sender: TObject); + procedure Rename1Click(Sender: TObject); + private + { Private declarations } + + FTemplate: TBITemplate; + + IData, + IPanels, + IDashboards: TBITreeNode; + + procedure AddNewData(const AData:TDataItem); + procedure ChangeDataLabel(const AData:TDataItem); + function ChooseData(out AData:TVisualData):Boolean; + function ChoosePanel(out APanel:TBIPanel):Boolean; + function DoSetProperties(const AItem: TObject):Boolean; + function HasPanels:Boolean; + function NewOwner:TComponent; + + procedure RefreshDashboard(const ADashboard:TDashboard); + procedure RefreshDashboardItem(const AItem:TDashboardItem); + procedure RefreshData(const AData:TVisualData); + procedure RefreshItem(const AItem:TDashboardItem); + procedure RefreshPanel(const APanel:TBIPanel); + + procedure SetAddCaption(const AObject:TObject); + procedure SetProperties(const AData:TVisualData); overload; + procedure SetProperties(const APanel:TBIPanel); overload; + procedure SetProperties(const AItem:TDashboardItem); overload; + procedure SetDashboardProperties(const ADashboard:TDashboard); + + procedure TryAddNewItem(const AItems:TDashboardItems; + const AParent:TBITreeNode); + procedure TryImport(const AKind:TDataDefinitionKind); + procedure TryNewPanel; + public + { Public declarations } + + class function Edit(const AOwner:TComponent; const ATemplate:TBITemplate):Boolean; static; + + procedure Refresh(const ATemplate:TBITemplate); + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Grid.DBGrid.pas b/src/delphi/VCL/BI.VCL.Grid.DBGrid.pas index 3d0c71f..2a93c9c 100644 --- a/src/delphi/VCL/BI.VCL.Grid.DBGrid.pas +++ b/src/delphi/VCL/BI.VCL.Grid.DBGrid.pas @@ -12,7 +12,9 @@ interface {$IFDEF MSWINDOWS} WinAPI.Windows, {$ENDIF} - {$IFNDEF FPC} + {$IFDEF FPC} + BI.FPC, + {$ELSE} Messages, UITypes, System.Types, // <-- due to inlining {$ENDIF} @@ -22,8 +24,6 @@ interface type {$IFDEF FPC} - TProc=procedure(const Value:T); - TDrawCellEvent=TOnDrawCell; {$ENDIF} @@ -37,6 +37,7 @@ TGridMenu=record public Alternate : TMenuItem; Button : TSpeedButton; + Colorize : TMenuItem; Detail : TMenuItem; Filters : TMenuItem; GroupBy : TMenuItem; @@ -99,16 +100,20 @@ TGridGroup=record procedure ApplyFilter(const AllowAllRows:Boolean; const ACol:Integer; const Value:String); function BIDataset:TBIDataset; function CalcSortWidth:Integer; + function CanColorize:Boolean; procedure ChangeDataSet(const ADataSet:TDataSet); procedure ChangedFilter(const ACol:Integer; const Value:String); procedure CheckDataSource; procedure CloseGroup(Sender:TObject); + function Colorizable:TDataColorizers; + procedure ColorizeClick(Sender:TObject); procedure DestroyMenu; function DetailItems:TDataArray; procedure DetailClicked(Sender: TObject); procedure DoGroupBy(Sender:TObject); procedure DoTitleClick(AColumn:TColumn); function GetData:TDataItem; + function GetDetail: TDataItem; procedure GroupDataChange(Sender: TObject; Field: TField); procedure MenuClick(Sender:TObject); procedure MenuFiltersClick(Sender: TObject); @@ -120,6 +125,7 @@ TGridGroup=record procedure ResetFeatures; procedure RowNumbersClick(Sender:TObject); procedure SetColumnSort(const Value:Boolean); + procedure SetDetail(const AData:TDataItem); function TitleWidth(const AColumn:TColumn):Integer; function TryColorize(const ARow,ACol:Integer; const AColumn:TColumn; out AIndex:Integer; out APercent:Double):Boolean; function TryFontColor(const AIndex:Integer; const ANewColor,ADefault:TColor):TColor; @@ -174,6 +180,7 @@ TGridGroup=record function ColumnOf(const AData:TDataItem):TColumn; overload; procedure Traverse(const AColumn:TColumn; const AProc:TProc); + property Detail:TDataItem read GetDetail write SetDetail; property MenuButton:TSpeedButton read IMenu.Button; property TopRow; published diff --git a/src/delphi/VCL/BI.VCL.Grid.pas b/src/delphi/VCL/BI.VCL.Grid.pas index 4abd108..f5ec543 100644 --- a/src/delphi/VCL/BI.VCL.Grid.pas +++ b/src/delphi/VCL/BI.VCL.Grid.pas @@ -14,7 +14,7 @@ interface System.UITypes, {$ENDIF} VCL.Controls, VCL.Forms, Data.DB, BI.Data, - BI.DataSource, BI.Dataset, VCL.Graphics, Vcl.Menus, + BI.DataSource, BI.Dataset, VCL.Graphics, Vcl.Menus, Vcl.ComCtrls, BI.UI, BI.VCL.DataControl, BI.Expression; type @@ -104,6 +104,7 @@ TBIGrid = class(TBIDataControl) FShowItems : TGridShowItems; procedure ChangedRow(Sender: TObject; Field: TField); + function GetCurrentRow: Integer; function GetDataSource: TDataSource; function GetReadOnly: Boolean; function GetTotals:Boolean; @@ -138,6 +139,7 @@ TBIGrid = class(TBIDataControl) procedure SetFilter(const AFilter:TLogicalExpression); property Plugin:TBIGridPlugin read IPlugin write SetPlugin; + property CurrentRow:Integer read GetCurrentRow; published property Alternate:TAlternateColor read FAlternate write SetAlternate; property DataSource:TDataSource read GetDataSource write SetDataSource; @@ -171,10 +173,12 @@ TUICommon=record class procedure AddForm(const AForm: TCustomForm; const AParent: TWinControl); static; class function AutoTest:Boolean; static; class function EditColor(const AOwner:TComponent; const AColor:TColor; out ANew:TColor):Boolean; static; + class function Input(const ATitle,ACaption,ADefault:String; out ANew:String):Boolean; static; class procedure LoadPosition(const AForm:TCustomForm; const Key:String); static; class procedure Popup(const APopup:TPopupMenu; const AParent:TControl); static; class procedure SavePosition(const AForm:TCustomForm; const Key:String); static; class function SelectFolder(var AFolder:String):Boolean; static; + class procedure ShowUnique(const ATab:TTabSheet); static; class function YesNo(const Message:String):Boolean; static; end; diff --git a/src/delphi/VCL/BI.VCL.GridForm.dfm b/src/delphi/VCL/BI.VCL.GridForm.dfm index 2d9942a..a4d4780 100644 --- a/src/delphi/VCL/BI.VCL.GridForm.dfm +++ b/src/delphi/VCL/BI.VCL.GridForm.dfm @@ -26,7 +26,6 @@ object BIGridForm: TBIGridForm Top = 0 Width = 411 Height = 34 - DataSource = DataSource1 VisibleButtons = [nbFirst, nbPrior, nbNext, nbLast] Align = alClient TabOrder = 0 @@ -58,17 +57,7 @@ object BIGridForm: TBIGridForm ParentBackground = False ParentColor = False TabOrder = 1 - DataSource = DataSource1 - end - object DataSource1: TDataSource - DataSet = BIDataset1 - OnDataChange = DataSource1DataChange - Left = 224 - Top = 264 - end - object BIDataset1: TBIDataset - RowNumbers = False - Left = 304 - Top = 264 + OnDataChange = GridDataChange + ExplicitTop = 5 end end diff --git a/src/delphi/VCL/BI.VCL.GridForm.pas b/src/delphi/VCL/BI.VCL.GridForm.pas index f1492df..6e1deed 100644 --- a/src/delphi/VCL/BI.VCL.GridForm.pas +++ b/src/delphi/VCL/BI.VCL.GridForm.pas @@ -8,19 +8,18 @@ interface {$ENDIF} System.SysUtils, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, BI.VCL.Grid, Data.DB, Vcl.ExtCtrls, - Vcl.DBCtrls, BI.Data, BI.DataSet, Vcl.StdCtrls, Vcl.Grids, Vcl.DBGrids; + Vcl.DBCtrls, BI.Data, Vcl.StdCtrls, Vcl.Grids, Vcl.DBGrids, + BI.VCL.DataControl; type TBIGridForm = class(TForm) - DataSource1: TDataSource; PanelNav: TPanel; DBNavigator1: TDBNavigator; Panel2: TPanel; LRow: TLabel; Grid: TBIGrid; - BIDataset1: TBIDataset; procedure FormShow(Sender: TObject); - procedure DataSource1DataChange(Sender: TObject; Field: TField); + procedure GridDataChange(Sender: TObject); private { Private declarations } public diff --git a/src/delphi/VCL/BI.VCL.Tree.TeeTree.pas b/src/delphi/VCL/BI.VCL.Tree.TeeTree.pas new file mode 100644 index 0000000..ae9d0ed --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Tree.TeeTree.pas @@ -0,0 +1,85 @@ +{*********************************************} +{ TeeBI Software Library } +{ Plugin TBITree class for VCL TeeTree } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} +unit BI.VCL.Tree.TeeTree; +{.$DEFINE FMX} + +interface + +uses + System.Classes, + TeeTree, + + {$IFDEF FMX} + FMX.Controls, BI.FMX.Tree, + {$ELSE} + VCL.Controls, BI.VCL.Tree, + {$ENDIF} + + BI.Arrays; + +type + TTeeTreePlugin=class(TBITreePlugin) + private + FAllowDelete : Boolean; + FTree : TTree; + FTreeOnChange : TNotifyEvent; + FTreeOnCheck : TNotifyEvent; + + procedure TreeChecked(Sender:TObject); + procedure TreeClick(Sender:TObject); + + {$IFDEF FMX} + procedure TreeKeyUp(Sender: TObject; var Key: Word; var KeyChar: WideChar; Shift: TShiftState); + {$ELSE} + procedure TreeKeyUp(Sender:TObject; var Key:Word; Shift:TShiftState); + {$ENDIF} + + protected + procedure BeginUpdating; override; + procedure Clear(const ANode:TBITreeNode=nil); override; + procedure ClearData(const ANode:TBITreeNode); override; + procedure EndUpdating; override; + function GetAllowDelete: Boolean; override; + function GetControl:TControl; override; + function GetCount:Integer; override; + function GetNode(const AIndex:Integer):TBITreeNode; override; + function GetOnChange: TNotifyEvent; override; + function GetOnCheck: TNotifyEvent; override; + function GetSelected:TBITreeNode; override; + function GetSelectedData: TBITreePlugin.TNodeData; override; + function NodeAt(const X,Y:Integer):TBITreeNode; override; + function SelectedText:String; override; + procedure SetAllowDelete(const Value: Boolean); override; + procedure SetData(const ANode: TBITreeNode; const AData: TObject); override; + procedure SetOnChange(const Value: TNotifyEvent); override; + procedure SetOnCheck(const Value: TNotifyEvent); override; + procedure SetSelected(const Value: TBITreeNode); override; + public + Constructor Create(const AOwner:TComponent); override; + + function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; override; + function ChildrenCount(const ANode:TBITreeNode):Integer; override; + + function DataOf(const ANode:TBITreeNode):TObject; override; + procedure Expand(const AIndex:Integer); override; + procedure Expand(const ANode:TBITreeNode; const DoExpand:Boolean=True; const Recursive:Boolean=False); override; + + function Find(const ATag:TObject; const AIndex:Integer):TBITreeNode; override; + function FirstNode:TBITreeNode; override; + function IsChecked(const ANode:TBITreeNode):Boolean; override; + function IsExpanded(const ANode:TBITreeNode):Boolean; override; + function NewNode(const AParent:TBITreeNode; const AText:String; + const ATag:TObject=nil; const AIndex:TInteger=-1):TBITreeNode; override; + function NextNode(const ANode:TBITreeNode):TBITreeNode; override; + function ParentOf(const ANode:TBITreeNode):TBITreeNode; override; + procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); override; + procedure SetText(const ANode:TBITreeNode; const Value:String); override; + function SiblingIndex(const ANode:TBITreeNode):Integer; override; + function TextOf(const ANode:TBITreeNode):String; override; + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Tree.TreeView.pas b/src/delphi/VCL/BI.VCL.Tree.TreeView.pas index 9673335..fe5a2a6 100644 --- a/src/delphi/VCL/BI.VCL.Tree.TreeView.pas +++ b/src/delphi/VCL/BI.VCL.Tree.TreeView.pas @@ -1,3 +1,9 @@ +{*********************************************} +{ TeeBI Software Library } +{ Plugin TBITree class for VCL TTreeView } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{*********************************************} unit BI.VCL.Tree.TreeView; interface @@ -20,12 +26,12 @@ TBITreeViewPlugin=class(TBITreePlugin) procedure TreeKeyUp(Sender:TObject; var Key:Word; Shift:TShiftState); protected procedure BeginUpdating; override; - procedure Clear; override; + procedure Clear(const ANode:TBITreeNode=nil); override; + procedure ClearData(const ANode:TBITreeNode); override; procedure EndUpdating; override; function GetAllowDelete: Boolean; override; function GetControl:TControl; override; function GetCount:Integer; override; - function GetData(const ANode:TBITreeNode):TObject; override; function GetNode(const AIndex:Integer):TBITreeNode; override; function GetOnChange: TNotifyEvent; override; function GetOnCheck: TNotifyEvent; override; @@ -44,21 +50,22 @@ TBITreeViewPlugin=class(TBITreePlugin) function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; override; function ChildrenCount(const ANode:TBITreeNode):Integer; override; + function DataOf(const ANode:TBITreeNode):TObject; override; procedure Expand(const AIndex:Integer); override; procedure Expand(const ANode:TBITreeNode; const DoExpand:Boolean=True; const Recursive:Boolean=False); override; function Find(const ATag:TObject; const AIndex:Integer):TBITreeNode; override; - function FirstNode:TBITreeNode; override; - function NextNode(const ANode:TBITreeNode):TBITreeNode; override; - function IsChecked(const ANode:TBITreeNode):Boolean; override; + function IsExpanded(const ANode:TBITreeNode):Boolean; override; function NewNode(const AParent:TBITreeNode; const AText:String; const ATag:TObject=nil; const AIndex:TInteger=-1):TBITreeNode; override; + function NextNode(const ANode:TBITreeNode):TBITreeNode; override; function ParentOf(const ANode:TBITreeNode):TBITreeNode; override; procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); override; + procedure SetText(const ANode:TBITreeNode; const Value:String); override; function SiblingIndex(const ANode:TBITreeNode):Integer; override; - function TextOf(const ANode:TBITreeNode):String; override; + function TextOf(const ANode:TBITreeNode):String; override; end; implementation diff --git a/src/delphi/VCL/BI.VCL.Tree.VirtualTreeView.pas b/src/delphi/VCL/BI.VCL.Tree.VirtualTreeView.pas new file mode 100644 index 0000000..d91409a --- /dev/null +++ b/src/delphi/VCL/BI.VCL.Tree.VirtualTreeView.pas @@ -0,0 +1,78 @@ +{************************************************} +{ TeeBI Software Library } +{ Plugin TBITree class for VCL TVirtualTreeView } +{ Copyright (c) 2015-2016 by Steema Software } +{ All Rights Reserved } +{************************************************} +unit BI.VCL.Tree.VirtualTreeView; + +interface + +uses + System.Classes, System.Generics.Collections, + VCL.Controls, VirtualTrees, + BI.Arrays, BI.VCL.Tree; + +type + TVirtualTreeTexts=TDictionary; + + TVirtualTreePlugin=class(TBITreePlugin) + private + FAllowDelete : Boolean; + FTexts : TVirtualTreeTexts; + FTree : TVirtualStringTree; + FTreeOnChange : TNotifyEvent; + FTreeOnCheck : TNotifyEvent; + + procedure ChangedTree(Sender: TBaseVirtualTree; Node: PVirtualNode); + procedure ToggleChecked(const ANode:TBITreeNode); + procedure TreeClick(Sender:TObject); + procedure TreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; + TextType: TVSTTextType; var CellText: string); + procedure TreeKeyUp(Sender:TObject; var Key:Word; Shift:TShiftState); + protected + procedure BeginUpdating; override; + procedure Clear(const ANode:TBITreeNode=nil); override; + procedure ClearData(const ANode:TBITreeNode); override; + procedure EndUpdating; override; + function GetAllowDelete: Boolean; override; + function GetControl:TControl; override; + function GetCount:Integer; override; + function GetNode(const AIndex:Integer):TBITreeNode; override; + function GetOnChange: TNotifyEvent; override; + function GetOnCheck: TNotifyEvent; override; + function GetSelected:TBITreeNode; override; + function GetSelectedData: TBITreePlugin.TNodeData; override; + function NodeAt(const X,Y:Integer):TBITreeNode; override; + function SelectedText:String; override; + procedure SetAllowDelete(const Value: Boolean); override; + procedure SetData(const ANode: TBITreeNode; const AData: TObject); override; + procedure SetOnChange(const Value: TNotifyEvent); override; + procedure SetOnCheck(const Value: TNotifyEvent); override; + procedure SetSelected(const Value: TBITreeNode); override; + public + Constructor Create(const AOwner:TComponent); override; + Destructor Destroy; override; + + function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; override; + function ChildrenCount(const ANode:TBITreeNode):Integer; override; + + function DataOf(const ANode:TBITreeNode):TObject; override; + procedure Expand(const AIndex:Integer); override; + procedure Expand(const ANode:TBITreeNode; const DoExpand:Boolean=True; const Recursive:Boolean=False); override; + + function Find(const ATag:TObject; const AIndex:Integer):TBITreeNode; override; + function FirstNode:TBITreeNode; override; + function IsChecked(const ANode:TBITreeNode):Boolean; override; + function IsExpanded(const ANode:TBITreeNode):Boolean; override; + function NewNode(const AParent:TBITreeNode; const AText:String; + const ATag:TObject=nil; const AIndex:TInteger=-1):TBITreeNode; override; + function NextNode(const ANode:TBITreeNode):TBITreeNode; override; + function ParentOf(const ANode:TBITreeNode):TBITreeNode; override; + procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); override; + procedure SetText(const ANode:TBITreeNode; const Value:String); override; + function SiblingIndex(const ANode:TBITreeNode):Integer; override; + function TextOf(const ANode:TBITreeNode):String; override; + end; + +implementation diff --git a/src/delphi/VCL/BI.VCL.Tree.pas b/src/delphi/VCL/BI.VCL.Tree.pas index 0315a5a..51d6ca1 100644 --- a/src/delphi/VCL/BI.VCL.Tree.pas +++ b/src/delphi/VCL/BI.VCL.Tree.pas @@ -34,27 +34,24 @@ TNodeData=class public Index : TInteger; - //{$IFDEF AUTOREFCOUNT}[Weak]{$ENDIF} - //Node : Integer; - {$IFDEF AUTOREFCOUNT}[Weak]{$ENDIF} Tag : TObject; end; - private - IDatas : Array of TNodeData; - protected + IData : Array of TNodeData; + FOnDelete : TNotifyEvent; procedure BeginUpdating; virtual; abstract; - procedure Clear; virtual; abstract; - procedure ClearData; + procedure Clear(const ANode:TBITreeNode=nil); virtual; abstract; + procedure ClearData; overload; + procedure ClearData(const ANode:TBITreeNode); overload; virtual; abstract; + procedure DeleteData(const AData:TNodeData); procedure EndUpdating; virtual; abstract; function GetAllowDelete: Boolean; virtual; abstract; function GetControl:TControl; virtual; abstract; function GetCount:Integer; virtual; abstract; - function GetData(const ANode:TBITreeNode):TObject; virtual; abstract; function GetNode(const AIndex:Integer):TBITreeNode; virtual; abstract; function GetOnChange: TNotifyEvent; virtual; abstract; function GetOnCheck: TNotifyEvent; virtual; abstract; @@ -75,6 +72,7 @@ TNodeData=class function Children(const ANode:TBITreeNode; const AIndex:Integer):TBITreeNode; virtual; abstract; function ChildrenCount(const ANode:TBITreeNode):Integer; virtual; abstract; + function DataOf(const ANode:TBITreeNode):TObject; virtual; abstract; procedure Expand(const AIndex:Integer); overload; virtual; abstract; procedure Expand(const ANode:TBITreeNode; @@ -87,6 +85,7 @@ TNodeData=class function NextNode(const ANode:TBITreeNode):TBITreeNode; virtual; abstract; function IsChecked(const ANode:TBITreeNode):Boolean; virtual; abstract; + function IsExpanded(const ANode:TBITreeNode):Boolean; virtual; abstract; function NewNode(const AParent:TBITreeNode; const AText:String; const ATag:TObject=nil; @@ -95,6 +94,7 @@ TNodeData=class function ParentOf(const ANode:TBITreeNode):TBITreeNode; virtual; abstract; procedure SetChecked(const ANode:TBITreeNode; const Value:Boolean); virtual; abstract; + procedure SetText(const ANode:TBITreeNode; const Value:String); virtual; abstract; function SiblingIndex(const ANode:TBITreeNode):Integer; virtual; abstract; function TextOf(const ANode:TBITreeNode):String; virtual; abstract; @@ -112,6 +112,7 @@ TBITreePluginClass=class of TBITreePlugin; // Generic Tree control that fills nodes from TDataItem relationships + {$IFNDEF FPC} {$IF CompilerVersion>=23} [ComponentPlatformsAttribute(pidWin32 or pidWin64 or pidOSX32 {$IF CompilerVersion>=25}or pidiOSSimulator or pidiOSDevice{$ENDIF} @@ -119,6 +120,7 @@ TBITreePluginClass=class of TBITreePlugin; {$IF CompilerVersion>=29}or pidiOSDevice64{$ENDIF} )] {$ENDIF} + {$ENDIF} TBITree=class(TBIDataControl) public type @@ -136,14 +138,17 @@ TBITreeNodes=class private FNodes : TBITreeNodes; FOnDeleting : TNotifyEvent; + FPlugin : TBITreePlugin; + function GetAllowDelete: Boolean; function GetOnChange: TNotifyEvent; function GetSelected: TBITreeNode; + procedure SetAllowDelete(const Value: Boolean); procedure SetOnChange(const Value: TNotifyEvent); procedure SetSelected(const Value: TBITreeNode); - function GetAllowDelete: Boolean; - procedure SetAllowDelete(const Value: Boolean); + procedure SetPlugin(const APlugin:TBITreePlugin); protected + procedure ChangeDragMode; procedure DeletedNode(Sender:TObject); procedure Loaded; override; procedure SetDataDirect(const Value: TDataItem); override; @@ -151,9 +156,6 @@ TBITreeNodes=class class var Engine : TBITreePluginClass; - var - Plugin : TBITreePlugin; - Constructor Create(AOwner:TComponent); override; Destructor Destroy; override; @@ -162,7 +164,9 @@ TBITreeNodes=class procedure BeginUpdating; // <-- not "BeginUpdate" due to conflict with FMX - procedure Clear; + procedure ChangePlugin(const APluginClass:TBITreePluginClass); + + procedure Clear(const ANode:TBITreeNode=nil); function DataOf(const ANode:TBITreeNode):TObject; procedure EndUpdating; @@ -178,6 +182,8 @@ TBITreeNodes=class procedure FillStore(const AStore:String); procedure FillStores; + function Find(const AText:String):TBITreeNode; + function NodeAt(const X,Y:Integer):TBITreeNode; function ParentOf(const ANode:TBITreeNode):TBITreeNode; @@ -188,6 +194,7 @@ TBITreeNodes=class procedure SetNodeData(const ANode:TBITreeNode; const AData:TObject); property Nodes:TBITreeNodes read FNodes; + property Plugin:TBITreePlugin read FPlugin write SetPlugin; property Selected:TBITreeNode read GetSelected write SetSelected; published property AllowDelete:Boolean read GetAllowDelete write SetAllowDelete default False;