Codeunit 9180 Generic Chart Mgt, source in 29
Source29
src/Layers/W1/BaseApp/System/GenericChart/GenericChartMgt.Codeunit.al979 lines, Copyright (c) Microsoft Corporation. MIT
namespace System.Visualization;
using System;
using System.Apps;
using System.Environment;
using System.Globalization;
using System.Reflection;
codeunit 9180 "Generic Chart Mgt"
{
trigger OnRun()
begin
end;
var
#pragma warning disable AA0470
MustSelectFieldErr: Label 'You must select the %1.';
#pragma warning restore AA0470
NoFiltersSelectedTxt: Label '(No filters selected)';
#pragma warning disable AA0470
TooManyMeasuresErr: Label 'You cannot select more than %1 measures when using the Customize Chart option.';
#pragma warning restore AA0470
CountColumnNotFoundErr: Label 'You cannot select Count for this chart because the source query does not support this aggregation method.';
#pragma warning disable AA0470
AggregationTypeForDecimalOnlyErr: Label 'The aggregation type %1 can only be selected for columns of type Decimal.';
#pragma warning restore AA0470
DescriptionTok: Label 'DESCR.', Comment = 'DESCR.';
XAxisTitleTok: Label 'X-TITLE', Comment = 'X-AXIS';
YAxisTitleTok: Label 'Y-TITLE', Comment = 'Y-AXIS';
ZAxisTitleTok: Label 'Z-TITLE', Comment = 'Y-AXIS';
XAxisCaptionTok: Label 'X-CAPTION', Comment = 'X-AXIS';
ZAxisCaptionTok: Label 'Z-CAPTION', Comment = 'Y-AXIS';
RequiredTok: Label 'REQUIRED', Comment = 'REQUIRED';
Optional1Tok: Label 'OPTIONAL1', Comment = 'OPTIONAL1';
Optional2Tok: Label 'OPTIONAL2', Comment = 'OPTIONAL2';
Optional3Tok: Label 'OPTIONAL3', Comment = 'OPTIONAL3';
Optional4Tok: Label 'OPTIONAL4', Comment = 'OPTIONAL4';
Optional5Tok: Label 'OPTIONAL5', Comment = 'OPTIONAL5';
AggregationTxt: Label 'None,Count,Sum,Min,Max,Avg';
[Scope('OnPrem')]
procedure RetrieveXML(var Chart: Record Chart; var TempGenericChartSetup: Record "Generic Chart Setup" temporary; var TempGenericChartYAxis: Record "Generic Chart Y-Axis" temporary; var TempGenericChartCaptionsBuf: Record "Generic Chart Captions Buffer" temporary; var TempGenericChartMemoBuf: Record "Generic Chart Memo Buffer" temporary; var TempGenericChartFilter: Record "Generic Chart Filter" temporary)
var
chartBuilder: DotNet BusinessChartBuilder;
i: Integer;
FilterText: Text[250];
CaptionCode: Code[10];
begin
TempGenericChartSetup.DeleteAll();
Clear(TempGenericChartSetup);
TempGenericChartCaptionsBuf.DeleteAll();
Clear(TempGenericChartCaptionsBuf);
TempGenericChartMemoBuf.DeleteAll();
Clear(TempGenericChartMemoBuf);
if not GetChartBuilder(Chart, chartBuilder) then
exit;
if chartBuilder.TableId > 0 then begin
TempGenericChartSetup."Source Type" := TempGenericChartSetup."Source Type"::Table;
TempGenericChartSetup."Source ID" := chartBuilder.TableId;
TempGenericChartSetup."Object Name" := chartBuilder.TableName;
end else begin
TempGenericChartSetup."Source Type" := TempGenericChartSetup."Source Type"::Query;
TempGenericChartSetup."Source ID" := chartBuilder.QueryId;
TempGenericChartSetup."Object Name" := chartBuilder.QueryName;
end;
GetSourceIDName(TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartSetup."Object Name");
BuildMemoBuf(TempGenericChartMemoBuf, DescriptionCode(), chartBuilder.GetMultilanguageDescription());
// Filters:
Clear(FilterText);
BuildTempGenericChartFilter(TempGenericChartSetup, TempGenericChartFilter, chartBuilder, FilterText);
TempGenericChartSetup."Filter Text" := FilterText;
FinalizeFilterText(TempGenericChartSetup."Filter Text");
// X, Y and Z axes:
TempGenericChartSetup."X-Axis Field ID" := chartBuilder.XDimensionId;
// Number of field
TempGenericChartSetup."X-Axis Field Name" := chartBuilder.XDimensionName;
// Name of field
GetFieldColumnNoName(TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartSetup."X-Axis Field ID", TempGenericChartSetup."X-Axis Field Name", false);
TempGenericChartSetup."X-Axis Show Title" := chartBuilder.ShowXDimensionTitle;
BuildCaptionBuf(TempGenericChartCaptionsBuf, XAxisTitleCode(), chartBuilder.GetXDimensionMultilanguageTitle());
BuildCaptionBuf(TempGenericChartCaptionsBuf, XAxisCaptionCode(), chartBuilder.GetXDimensionMultilanguageCaption());
TempGenericChartSetup."Y-Axis Show Title" := chartBuilder.ShowYAxisTitle;
BuildCaptionBuf(TempGenericChartCaptionsBuf, YAxisTitleCode(), chartBuilder.GetYAxisMultilanguageTitle());
if chartBuilder.HasZDimension then begin
TempGenericChartSetup."Z-Axis Field ID" := chartBuilder.ZDimensionId();
TempGenericChartSetup."Z-Axis Field Name" := chartBuilder.ZDimensionName();
GetFieldColumnNoName(TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartSetup."Z-Axis Field ID", TempGenericChartSetup."Z-Axis Field Name", false);
TempGenericChartSetup."Z-Axis Show Title" := chartBuilder.ShowZDimensionTitle();
BuildCaptionBuf(TempGenericChartCaptionsBuf, ZAxisTitleCode(), chartBuilder.GetZDimensionMultilanguageTitle());
BuildCaptionBuf(TempGenericChartCaptionsBuf, ZAxisCaptionCode(), chartBuilder.GetZDimensionMultilanguageCaption());
end;
// Measures:
TempGenericChartYAxis.DeleteAll();
CaptionCode := RequiredMeasureCode();
for i := 0 to chartBuilder.MeasureCount - 1 do begin
TempGenericChartYAxis.Init();
TempGenericChartYAxis.ID := Chart.ID;
TempGenericChartYAxis."Line No." := 10000 * (i + 1);
if chartBuilder.HasMeasureField(i) then begin
TempGenericChartYAxis."Y-Axis Measure Field ID" := chartBuilder.GetMeasureId(i);
TempGenericChartYAxis."Y-Axis Measure Field Name" := chartBuilder.GetMeasureName(i);
BuildCaptionBuf(TempGenericChartCaptionsBuf, CaptionCode, chartBuilder.GetMultilanguageMeasureCaption(i));
GetFieldColumnNoName(
TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartYAxis."Y-Axis Measure Field ID",
TempGenericChartYAxis."Y-Axis Measure Field Name", false);
if CaptionCode = RequiredMeasureCode() then
CaptionCode := OptionalMeasure1Code()
else
CaptionCode := IncStr(CaptionCode)
end;
TempGenericChartYAxis."Chart Type" := ChartType2GraphType(chartBuilder.GetMeasureChartType(i));
TempGenericChartYAxis.Aggregation := Operator2Aggregation(chartBuilder.GetMeasureOperator(i));
TempGenericChartYAxis.Insert();
end;
end;
[Scope('OnPrem')]
procedure FillChartHelper(var chartBuilder: DotNet BusinessChartBuilder; TempGenericChartSetup: Record "Generic Chart Setup" temporary; var TempGenericChartYAxis: Record "Generic Chart Y-Axis" temporary; var TempGenericChartFilter: Record "Generic Chart Filter" temporary; var TempGenericChartCaptionsBuf: Record "Generic Chart Captions Buffer" temporary; var TempGenericChartMemoBuf: Record "Generic Chart Memo Buffer" temporary)
var
DataMeasureType: DotNet DataMeasureType;
DataAggregationType: DotNet DataAggregationType;
MultilanguageText: DotNet BusinessChartMultiLanguageText;
CaptionCode: Code[10];
begin
ValidateChart(TempGenericChartSetup, TempGenericChartYAxis, TempGenericChartFilter);
case TempGenericChartSetup."Source Type" of
TempGenericChartSetup."Source Type"::Table:
begin
chartBuilder.TableId(TempGenericChartSetup."Source ID");
chartBuilder.TableName(TempGenericChartSetup."Object Name");
end;
TempGenericChartSetup."Source Type"::Query:
begin
chartBuilder.QueryId(TempGenericChartSetup."Source ID");
chartBuilder.QueryName(TempGenericChartSetup."Object Name");
end;
end;
BuildMemoMultilanguageText(TempGenericChartMemoBuf, DescriptionCode(), MultilanguageText);
chartBuilder.SetMultilanguageDescription(MultilanguageText);
chartBuilder.XDimensionId := TempGenericChartSetup."X-Axis Field ID";
chartBuilder.XDimensionName := TempGenericChartSetup."X-Axis Field Name";
chartBuilder.ShowXDimensionTitle := TempGenericChartSetup."X-Axis Show Title";
BuildMultilanguageText(TempGenericChartCaptionsBuf, XAxisTitleCode(), MultilanguageText);
chartBuilder.SetXDimensionMultilanguageTitle(MultilanguageText);
BuildMultilanguageText(TempGenericChartCaptionsBuf, XAxisCaptionCode(), MultilanguageText);
chartBuilder.SetXDimensionMultilanguageCaption(MultilanguageText);
chartBuilder.ZDimensionId := TempGenericChartSetup."Z-Axis Field ID";
chartBuilder.ZDimensionName := TempGenericChartSetup."Z-Axis Field Name";
chartBuilder.ShowZDimensionTitle := TempGenericChartSetup."Z-Axis Show Title";
BuildMultilanguageText(TempGenericChartCaptionsBuf, ZAxisTitleCode(), MultilanguageText);
chartBuilder.SetZDimensionMultilanguageTitle(MultilanguageText);
BuildMultilanguageText(TempGenericChartCaptionsBuf, ZAxisCaptionCode(), MultilanguageText);
chartBuilder.SetZDimensionMultilanguageCaption(MultilanguageText);
// Y-Axis
chartBuilder.ShowYAxisTitle := TempGenericChartSetup."Y-Axis Show Title";
BuildMultilanguageText(TempGenericChartCaptionsBuf, YAxisTitleCode(), MultilanguageText);
chartBuilder.SetYAxisMultilanguageTitle(MultilanguageText);
if TempGenericChartYAxis.Find('-') then begin
CaptionCode := RequiredMeasureCode();
repeat
BuildMultilanguageText(TempGenericChartCaptionsBuf, CaptionCode, MultilanguageText);
DataMeasureType := GraphType2ChartType(TempGenericChartYAxis."Chart Type");
DataAggregationType := Aggregation2Operator(TempGenericChartYAxis.Aggregation);
chartBuilder.AddMeasure(
TempGenericChartYAxis."Y-Axis Measure Field ID", TempGenericChartYAxis."Y-Axis Measure Field Name", MultilanguageText, DataMeasureType, DataAggregationType);
if CaptionCode = RequiredMeasureCode() then
CaptionCode := OptionalMeasure1Code()
else
CaptionCode := IncStr(CaptionCode)
until TempGenericChartYAxis.Next() = 0
end;
// Filters:
if TempGenericChartFilter.Find('-') then
repeat
GetFieldColumnNoName(
TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartFilter."Filter Field ID", TempGenericChartFilter."Filter Field Name", true);
if TempGenericChartFilter."Filter Field ID" > 0 then
case TempGenericChartSetup."Source Type" of
TempGenericChartSetup."Source Type"::Table:
chartBuilder.AddTableFilter(TempGenericChartFilter."Filter Field ID", TempGenericChartFilter."Filter Field Name", TempGenericChartFilter."Filter Value");
TempGenericChartSetup."Source Type"::Query:
chartBuilder.AddQueryFilter(TempGenericChartFilter."Filter Field ID", TempGenericChartFilter."Filter Field Name", TempGenericChartFilter."Filter Value");
end;
until TempGenericChartFilter.Next() = 0;
end;
[Scope('OnPrem')]
procedure SaveChanges(var Chart: Record Chart; TempGenericChartSetup: Record "Generic Chart Setup" temporary; var TempGenericChartYAxis: Record "Generic Chart Y-Axis" temporary; var TempGenericChartFilter: Record "Generic Chart Filter" temporary; var TempGenericChartCaptionsBuf: Record "Generic Chart Captions Buffer" temporary; var TempGenericChartMemoBuf: Record "Generic Chart Memo Buffer" temporary)
var
chartBuilder: DotNet BusinessChartBuilder;
OutStream: OutStream;
begin
chartBuilder := chartBuilder.Empty();
FillChartHelper(chartBuilder, TempGenericChartSetup, TempGenericChartYAxis, TempGenericChartFilter,
TempGenericChartCaptionsBuf, TempGenericChartMemoBuf);
Clear(Chart.BLOB);
Chart.BLOB.CreateOutStream(OutStream);
CopyStream(OutStream, chartBuilder.GetAsStream());
Clear(chartBuilder);
end;
procedure LookUpObjectId(ObjType: Option " ","Table","Query"; var ObjID: Integer; var ObjName: Text[50])
var
AllObjWithCaption: Record AllObjWithCaption;
begin
SetObjTypeRange(ObjType, AllObjWithCaption);
if PAGE.RunModal(PAGE::Objects, AllObjWithCaption) = ACTION::LookupOK then begin
ObjID := AllObjWithCaption."Object ID";
ValidateObjectID(ObjType, ObjID, ObjName);
end;
end;
procedure ValidateObjectID(ObjType: Option " ","Table","Query"; var ObjID: Integer; var ObjName: Text[50])
var
AllObjWithCaption: Record AllObjWithCaption;
begin
ObjName := '';
if ObjType = ObjType::" " then begin
ObjID := 0;
exit;
end;
SetObjTypeRange(ObjType, AllObjWithCaption);
AllObjWithCaption.SetRange("Object ID", ObjID);
if AllObjWithCaption.FindFirst() then
ObjName := AllObjWithCaption."Object Name";
end;
[Scope('OnPrem')]
procedure ValidateFieldColumn(TempGenericChartSetup: Record "Generic Chart Setup" temporary; var FieldColumnNo: Integer; FieldColumnName: Text[80]; var FieldCaption: Text[250]; Category: Integer; FilteringLookup: Boolean; var Aggregation: Option "None","Count","Sum","Min","Max",Avg)
var
"Field": Record "Field";
TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary;
begin
// Category: 0: All, 1: Not integer and decimal, 2: Only integer and decimal
CheckSourceTypeID(TempGenericChartSetup, true);
FieldColumnNo := 0;
FieldCaption := '';
if FieldColumnName = '' then begin
Aggregation := Aggregation::None;
exit;
end;
case TempGenericChartSetup."Source Type" of
TempGenericChartSetup."Source Type"::Table:
begin
Field.SetRange(TableNo, TempGenericChartSetup."Source ID");
Field.SetRange(FieldName, FieldColumnName);
Field.SetFilter(ObsoleteState, '<>%1', Field.ObsoleteState::Removed);
FilterFieldCategory(Field, Category, FilteringLookup);
Field.FindFirst();
FieldColumnNo := Field."No.";
end;
TempGenericChartSetup."Source Type"::Query:
begin
GetQueryColumnList(TempGenericChartQueryColumn, TempGenericChartSetup."Source ID", Category, FilteringLookup);
TempGenericChartQueryColumn.SetRange("Query No.", TempGenericChartSetup."Source ID");
TempGenericChartQueryColumn.SetRange("Column Name", FieldColumnName);
TempGenericChartQueryColumn.FindFirst();
FieldColumnNo := TempGenericChartQueryColumn."Query Column No.";
FieldColumnName := TempGenericChartQueryColumn."Column Name";
Aggregation := TempGenericChartQueryColumn."Aggregation Type";
end;
end;
FieldCaption := FieldColumnName;
end;
[Scope('OnPrem')]
procedure RetrieveFieldColumn(TempGenericChartSetup: Record "Generic Chart Setup" temporary; var No: Integer; var Name: Text[80]; var Capt: Text[250]; Category: Integer; FilteringLookup: Boolean)
var
"Field": Record "Field";
TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary;
FieldSelection: Codeunit "Field Selection";
begin
// Category: 0: All, 1: Not integer and decimal, 2: Only integer and decimal
CheckSourceTypeID(TempGenericChartSetup, true);
case TempGenericChartSetup."Source Type" of
TempGenericChartSetup."Source Type"::Table:
begin
Field.SetRange(TableNo, TempGenericChartSetup."Source ID");
FilterFieldCategory(Field, Category, FilteringLookup);
if FieldSelection.Open(Field) then begin
No := Field."No.";
Name := Field.FieldName;
Capt := Name;
end;
end;
TempGenericChartSetup."Source Type"::Query:
begin
GetQueryColumnList(TempGenericChartQueryColumn, TempGenericChartSetup."Source ID", Category, FilteringLookup);
TempGenericChartQueryColumn.SetRange("Query No.", TempGenericChartSetup."Source ID");
if PAGE.RunModal(PAGE::"Generic Chart Query Columns", TempGenericChartQueryColumn) = ACTION::LookupOK then begin
No := TempGenericChartQueryColumn."Query Column No.";
Name := TempGenericChartQueryColumn."Column Name";
Capt := Name;
end;
end;
end;
end;
[Scope('OnPrem')]
procedure RetrieveFieldColumnIDFromName(ObjType: Option " ","Table","Query"; ObjID: Integer; var No: Integer; Name: Text[50])
var
"Field": Record "Field";
TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary;
begin
No := 0;
case ObjType of
ObjType::Table:
begin
Field.SetRange(TableNo, ObjID);
Field.SetRange(FieldName, Name);
Field.SetFilter(ObsoleteState, '<>%1', Field.ObsoleteState::Removed);
if Field.FindFirst() then
No := Field."No.";
end;
ObjType::Query:
begin
GetQueryColumnList(TempGenericChartQueryColumn, ObjID, 0, true);
TempGenericChartQueryColumn.SetRange("Query No.", ObjID);
TempGenericChartQueryColumn.SetRange("Column Name", Name);
if TempGenericChartQueryColumn.FindFirst() then
No := TempGenericChartQueryColumn."Query Column No.";
end;
end;
end;
procedure SetObjTypeRange(ObjType: Option " ","Table","Query"; var AllObjWithCaption: Record AllObjWithCaption)
begin
Clear(AllObjWithCaption);
case ObjType of
ObjType::Table:
AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Table);
ObjType::Query:
AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Query);
end;
end;
local procedure ChartType2GraphType(DataMeasureType: DotNet DataMeasureType): Integer
var
i: Integer;
begin
i := DataMeasureType;
case i of
10: // Column
exit(0);
0:
exit(1);
3:
exit(2);
11:
exit(3);
12:
exit(4);
13:
exit(5);
15:
exit(6);
16:
exit(7);
5:
exit(8);
17:
exit(9);
18:
exit(10);
21:
exit(11);
25:
exit(12);
33:
exit(13);
end;
end;
local procedure GraphType2ChartType(GraphType: Integer): Integer
begin
// Save function:
// Aggregation var on page 9183:
// Column,Point,Line,ColumnStacked,ColumnStacked100,Area,AreaStacked,AreaStacked100,StepLine,Pie,Doughnut,Range,Radar,Funnel
// option in TAB485:
// Point,1,Bubble,Line,4,StepLine,6,7,8,9,Column,StackedColumn,StackedColumn100,Area,14,StackedArea,StackedArea100,Pie,Doughnut,19,20,Range,22,23,24,Radar,26,27,28,29,30,31,32,Funnel}
case GraphType of
0:
exit(10); // Column
1:
exit(0); // Point
2:
exit(3); // Line
3:
exit(11); // ColumnStacked
4:
exit(12); // ColumnStacked100
5:
exit(13); // Area
6:
exit(15); // AreaStacked
7:
exit(16); // AreaStacked100
8:
exit(5); // StepLine
9:
exit(17); // Pie
10:
exit(18); // Doughnut
11:
exit(21); // Range
12:
exit(25); // Radar
13:
exit(33); // Funnel
else
exit(GraphType);
end;
end;
local procedure Aggregation2Operator(Aggregation: Integer): Integer
begin
// From Rec (BLOB) to XML File - i.e. when saving
// Aggregation:
exit(Aggregation);
end;
local procedure Operator2Aggregation(Operator: Integer): Integer
begin
// Retrieve from XML (BLOB) to rec
exit(Operator);
end;
[Scope('OnPrem')]
procedure GetQueryColumnList(var TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary; ObjID: Integer; ColFilter: Integer; FilteringLookup: Boolean)
var
ApplicationObjectMetadata: Record "Application Object Metadata";
AllObj: Record AllObj;
metaData: DotNet QueryMetadataReader;
inStream: InStream;
begin
// Colfilter: = 0: All, 1: Only text etc (X- and Z-Axis), 2: Only decimal and integer (Y-axis)
Clear(TempGenericChartQueryColumn);
TempGenericChartQueryColumn.DeleteAll();
AllObj.Get(AllObj."Object Type"::Query, ObjID);
if not ApplicationObjectMetadata.Get(AllObj."App Runtime Package ID", ApplicationObjectMetadata."Object Type"::Query, ObjID) then
exit;
if not ApplicationObjectMetadata.Metadata.HasValue() then
exit;
ApplicationObjectMetadata.CalcFields(Metadata);
ApplicationObjectMetadata.Metadata.CreateInStream(inStream);
// Load into Query Metadata Reader and retrieve values
metaData := metaData.FromStream(inStream);
LoadQueryColumns(metaData, TempGenericChartQueryColumn, ObjID, ColFilter, FilteringLookup);
end;
local procedure FilterFieldCategory(var "Field": Record "Field"; Category: Integer; FilteringLookup: Boolean)
begin
case Category of
0:
Field.SetRange(Type);
1, 2:
Field.SetFilter(Type, TypeFilterText(Category));
end;
Field.SetRange(Class);
if not FilteringLookup then
Field.SetFilter(Class, '<>%1', Field.Class::FlowFilter);
end;
local procedure ValidateChart(TempGenericChartSetup: Record "Generic Chart Setup" temporary; var TempGenericChartYAxis: Record "Generic Chart Y-Axis" temporary; var TempGenericChartFilter: Record "Generic Chart Filter" temporary)
var
AllObjWithCaption: Record AllObjWithCaption;
DummyAggregation: Option "None","Count","Sum","Min","Max",Avg;
DummyCaption: Text[250];
DummyInt: Integer;
begin
case TempGenericChartSetup."Source Type" of
TempGenericChartSetup."Source Type"::Table:
AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Table);
TempGenericChartSetup."Source Type"::Query:
AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Query);
end;
AllObjWithCaption.SetRange("Object ID", TempGenericChartSetup."Source ID");
AllObjWithCaption.FindFirst();
if TempGenericChartYAxis.FindSet() then
repeat
ValidateFieldColumn(
TempGenericChartSetup, DummyInt, TempGenericChartYAxis."Y-Axis Measure Field Name", DummyCaption, 2, false, DummyAggregation);
until TempGenericChartYAxis.Next() = 0;
if TempGenericChartFilter.FindSet() then
repeat
ValidateFieldColumn(
TempGenericChartSetup, DummyInt, TempGenericChartFilter."Filter Field Name", DummyCaption, 0, true, DummyAggregation);
until TempGenericChartFilter.Next() = 0;
ValidateFieldColumn(TempGenericChartSetup, DummyInt, TempGenericChartSetup."X-Axis Field Name", TempGenericChartSetup."X-Axis Title", 0, false, DummyAggregation);
ValidateFieldColumn(TempGenericChartSetup, DummyInt, TempGenericChartSetup."Z-Axis Field Name", TempGenericChartSetup."Z-Axis Title", 0, false, DummyAggregation);
end;
local procedure LoadQueryColumns(var MetaData: DotNet QueryMetadataReader; var TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary; ObjID: Integer; FieldTypeFilter: Integer; FilteringLookup: Boolean)
var
FieldParam: Record "Field";
queryField: DotNet QueryFields;
i: Integer;
j: Integer;
InclInColumns: Boolean;
begin
// Field Type:
// Category: 0: All, 1: Not integer and decimal, 2: Only integer and decimal
// String,Integer,Decimal,DateTime
if MetaData.Fields.Count = 0 then
exit;
for i := 0 to MetaData.Fields.Count - 1 do begin
j := 0;
queryField := MetaData.Fields.Item(i);
InclInColumns := false;
if FilteringLookup or not queryField.IsFilterOnly then
InclInColumns := SetInclInColumns(FieldTypeFilter, queryField.TableNo, queryField.FieldNo, FieldParam);
if InclInColumns then begin
Clear(TempGenericChartQueryColumn);
TempGenericChartQueryColumn."Query No." := ObjID;
TempGenericChartQueryColumn."Query Column No." := queryField.ColumnId;
TempGenericChartQueryColumn."Column Name" := queryField.FieldName;
TempGenericChartQueryColumn.SetAggregationType(queryField.AggregationType);
TempGenericChartQueryColumn.SetColumnDataType(FieldParam.Type);
repeat
j += 1;
TempGenericChartQueryColumn."Entry No." := j;
until TempGenericChartQueryColumn.Insert();
end;
end;
end;
procedure CopyChart(var SourceChart: Record Chart; TargetChartID: Code[20]; TargetChartTitle: Text[50])
var
TargetChart: Record Chart;
begin
Clear(TargetChart);
TargetChart := SourceChart;
TargetChart.Validate(ID, TargetChartID);
if TargetChartTitle <> '' then
TargetChart.Validate(Name, TargetChartTitle)
else
TargetChart.Validate(Name, SourceChart.Name);
TargetChart.Insert(true);
end;
local procedure GetChartBuilder(var Chart: Record Chart; var chartBuilder: DotNet BusinessChartBuilder): Boolean
var
InStream: InStream;
begin
if not Chart.BLOB.HasValue() then
exit(false);
Chart.CalcFields(BLOB);
Chart.BLOB.CreateInStream(InStream);
chartBuilder := chartBuilder.FromStream(InStream);
exit(true);
end;
procedure BuildFilterText(var FilterText: Text[250]; Inp: Text[100])
begin
if FilterText <> '' then
AddToFilterText(FilterText, CopyStr(' ; ' + Inp, 1, MaxStrLen(FilterText)))
else
AddToFilterText(FilterText, CopyStr(Inp, 1, MaxStrLen(FilterText)));
end;
local procedure AddToFilterText(var FText: Text[250]; Inp: Text[100])
var
RemLgth: Integer;
begin
if StrLen(FText + Inp) <= MaxStrLen(FText) then begin
FText := FText + Inp;
exit;
end;
RemLgth := MaxStrLen(FText) - StrLen(FText);
if RemLgth > 3 then
FText := FText + ',...'
else
FText := PadStr(FText, MaxStrLen(FText), '.');
end;
procedure FinalizeFilterText(var InTxt: Text[250])
begin
if InTxt = '' then
InTxt := NoFiltersSelectedTxt;
end;
[Scope('OnPrem')]
procedure GetDescription(Chart: Record Chart): Text
var
chartBuilder: DotNet BusinessChartBuilder;
begin
if not GetChartBuilder(Chart, chartBuilder) then
exit('');
exit(chartBuilder.Description);
end;
[Scope('OnPrem')]
procedure ChartCustomization(var TempChart: Record Chart temporary): Boolean
begin
TempChart.Insert();
if NoOfMeasuresApplied(TempChart) > GetMaxNoOfMeasures() then begin
Message(TooManyMeasuresErr, GetMaxNoOfMeasures());
exit(false);
end;
exit(PAGE.RunModal(PAGE::"Generic Chart Customization", TempChart) = ACTION::LookupOK);
end;
local procedure NoOfMeasuresApplied(var TempChart: Record Chart): Integer
var
chartBuilder: DotNet BusinessChartBuilder;
begin
if not GetChartBuilder(TempChart, chartBuilder) then
exit(0);
exit(chartBuilder.MeasureCount);
end;
local procedure GetMaxNoOfMeasures(): Integer
begin
exit(6); // Max number of measures allowed when using the Chart Design pages 9183, 9188
end;
local procedure GetFieldColumnNoName(SourceType: Option " ","Table","Query"; SourceNo: Integer; var FieldColNo: Integer; var FieldColName: Text; FilteringLookup: Boolean)
var
TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary;
"Field": Record "Field";
Found: Boolean;
begin
case SourceType of
SourceType::Table:
if FieldColNo > 0 then begin
FieldColName := '';
if Field.Get(SourceNo, FieldColNo) then
FieldColName := Field.FieldName;
end else begin
Field.SetRange(TableNo, SourceNo);
if Field.FindSet() then
repeat
if UpperCase(Field.FieldName) = UpperCase(FieldColName) then begin
Found := true;
FieldColNo := Field."No.";
end;
until (Field.Next() = 0) or Found;
end;
SourceType::Query:
begin
GetQueryColumnList(TempGenericChartQueryColumn, SourceNo, 0, FilteringLookup);
if FieldColNo > 0 then begin
FieldColName := '';
TempGenericChartQueryColumn.SetRange("Query Column No.", FieldColNo);
if TempGenericChartQueryColumn.FindFirst() then
FieldColName := TempGenericChartQueryColumn."Column Name";
end else
if TempGenericChartQueryColumn.FindSet() then
repeat
if UpperCase(TempGenericChartQueryColumn."Column Name") = UpperCase(FieldColName) then begin
Found := true;
FieldColNo := TempGenericChartQueryColumn."Query Column No.";
end;
until (TempGenericChartQueryColumn.Next() = 0) or Found;
end;
end;
end;
local procedure GetSourceIDName(SourceType: Option " ","Table","Query"; var SourceID: Integer; var SourceName: Text)
var
AllObjWithCaption: Record AllObjWithCaption;
begin
case SourceType of
SourceType::Table:
AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Table);
SourceType::Query:
AllObjWithCaption.SetRange("Object Type", AllObjWithCaption."Object Type"::Query);
end;
if SourceID > 0 then begin
AllObjWithCaption.SetRange("Object ID", SourceID);
AllObjWithCaption.FindFirst();
SourceName := AllObjWithCaption."Object Name";
exit;
end;
if SourceName <> '' then begin
AllObjWithCaption.SetRange("Object Name", SourceName);
AllObjWithCaption.FindFirst();
SourceID := AllObjWithCaption."Object ID";
end;
end;
local procedure BuildTempGenericChartFilter(TempGenericChartSetup: Record "Generic Chart Setup" temporary; var TempGenericChartFilter: Record "Generic Chart Filter" temporary; var chartBuilder: DotNet BusinessChartBuilder; var FilterText: Text[250])
var
i: Integer;
begin
TempGenericChartFilter.DeleteAll();
case TempGenericChartSetup."Source Type" of
TempGenericChartSetup."Source Type"::Table:
for i := 0 to chartBuilder.TableFilterCount - 1 do begin
TempGenericChartFilter.Init();
TempGenericChartFilter.ID := TempGenericChartSetup.ID;
TempGenericChartFilter."Line No." := i + 1;
TempGenericChartFilter."Filter Field ID" := chartBuilder.GetTableFilterFieldId(i);
TempGenericChartFilter."Filter Field Name" := chartBuilder.GetTableFilterFieldName(i);
GetFieldColumnNoName(
TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartFilter."Filter Field ID", TempGenericChartFilter."Filter Field Name", true);
TempGenericChartFilter."Filter Value" := chartBuilder.GetTableFilterValue(i);
if TempGenericChartFilter."Filter Value" <> '' then
BuildFilterText(FilterText,
CopyStr(TempGenericChartFilter."Filter Field Name" + ' : ' + TempGenericChartFilter."Filter Value", 1, MaxStrLen(FilterText)));
TempGenericChartFilter.Insert();
end;
TempGenericChartSetup."Source Type"::Query:
for i := 0 to chartBuilder.QueryFilterCount - 1 do begin
TempGenericChartFilter.Init();
TempGenericChartFilter.ID := TempGenericChartSetup.ID;
TempGenericChartFilter."Line No." := i + 1;
TempGenericChartFilter."Filter Field ID" := chartBuilder.GetQueryFilterFieldId(i);
TempGenericChartFilter."Filter Field Name" := chartBuilder.GetQueryFilterFieldName(i);
GetFieldColumnNoName(
TempGenericChartSetup."Source Type", TempGenericChartSetup."Source ID", TempGenericChartFilter."Filter Field ID", TempGenericChartFilter."Filter Field Name", true);
TempGenericChartFilter."Filter Value" := chartBuilder.GetQueryFilterValue(i);
if TempGenericChartFilter."Filter Value" <> '' then
BuildFilterText(FilterText,
CopyStr(TempGenericChartFilter."Filter Field Name" + ' : ' + TempGenericChartFilter."Filter Value", 1, MaxStrLen(FilterText)));
TempGenericChartFilter.Insert();
end;
end;
end;
local procedure SetInclInColumns(FilterType: Integer; TableNumber: Integer; FieldNumber: Integer; var FieldType: Record "Field"): Boolean
var
"Field": Record "Field";
begin
if FieldNumber < 0 then
exit(false);
if FieldNumber = 0 then
exit(FilterType in [0, 2]);
// The column method is Count which is a numeral
Field.SetRange(TableNo, TableNumber);
Field.SetRange("No.", FieldNumber);
if FilterType > 0 then
Field.SetFilter(Type, TypeFilterText(FilterType));
if Field.FindFirst() then begin
FieldType.Type := Field.Type;
exit(true);
end;
exit(false);
end;
local procedure TypeFilterText(Category: Integer): Text
var
DummyField: Record "Field";
begin
case Category of
1:
exit(
StrSubstNo(
'%1|%2|%3|%4|%5|%6|%7', DummyField.Type::Date, DummyField.Type::Time, DummyField.Type::DateFormula, DummyField.Type::Text, DummyField.Type::Code, DummyField.Type::Option, DummyField.Type::DateTime));
2:
exit(StrSubstNo('%1|%2|%3|%4|%5', DummyField.Type::Decimal, DummyField.Type::Binary, DummyField.Type::Integer, DummyField.Type::BigInteger, DummyField.Type::Duration));
end;
end;
procedure CheckSourceTypeID(TempGenericChartSetup: Record "Generic Chart Setup" temporary; CheckSourceID: Boolean)
begin
if TempGenericChartSetup."Source Type" = TempGenericChartSetup."Source Type"::" " then
Error(MustSelectFieldErr, TempGenericChartSetup.FieldCaption("Source Type"));
if CheckSourceID then
if TempGenericChartSetup."Source ID" = 0 then
Error(MustSelectFieldErr, TempGenericChartSetup.FieldCaption("Source ID"));
end;
[Scope('OnPrem')]
procedure GetQueryCountColumnName(var TempGenericChartSetup: Record "Generic Chart Setup" temporary): Text[50]
var
TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary;
begin
if TempGenericChartSetup."Source Type" <> TempGenericChartSetup."Source Type"::Query then
exit('');
GetQueryColumnList(TempGenericChartQueryColumn, TempGenericChartSetup."Source ID", 0, true);
TempGenericChartQueryColumn.SetRange("Aggregation Type", TempGenericChartQueryColumn."Aggregation Type"::Count);
if not TempGenericChartQueryColumn.FindFirst() then
Error(CountColumnNotFoundErr);
exit(TempGenericChartQueryColumn."Column Name");
end;
[Scope('OnPrem')]
procedure CheckDataTypeAggregationCompliance(TempGenericChartSetup: Record "Generic Chart Setup" temporary; ColumnName: Text[50]; Aggregation: Option "None","Count","Sum","Min","Max",Avg)
var
TempGenericChartQueryColumn: Record "Generic Chart Query Column" temporary;
begin
if TempGenericChartSetup."Source Type" <> TempGenericChartSetup."Source Type"::Query then
exit;
if ColumnName = '' then
exit;
if Aggregation in [Aggregation::None, Aggregation::Count] then
exit;
GetQueryColumnList(TempGenericChartQueryColumn, TempGenericChartSetup."Source ID", 0, false);
TempGenericChartQueryColumn.SetRange("Column Name", ColumnName);
if not TempGenericChartQueryColumn.FindFirst() then
exit;
ValidateCompliance(TempGenericChartQueryColumn."Column Data Type", Aggregation);
end;
local procedure ValidateCompliance(ColumnDataType: Option Date,Time,DateFormula,Decimal,Text,"Code",Binary,Boolean,"Integer",Option,BigInteger,DateTime; Aggregation: Option "None","Count","Sum","Min","Max",Avg)
begin
if not (Aggregation in [Aggregation::Sum, Aggregation::Min, Aggregation::Max, Aggregation::Avg]) then
exit;
if ColumnDataType <> ColumnDataType::Decimal then
Error(AggregationTypeForDecimalOnlyErr, SelectStr(Aggregation + 1, AggregationTxt));
end;
procedure TextMLAssistEdit(var TempGenericChartCaptionsBuf: Record "Generic Chart Captions Buffer" temporary; CaptionCode: Code[10]): Text[250]
var
GenericChartTextEditor: Page "Generic Chart Text Editor";
begin
exit(GenericChartTextEditor.AssistEdit(TempGenericChartCaptionsBuf, CaptionCode))
end;
procedure MemoMLAssistEdit(var TempGenericChartMemoBuf: Record "Generic Chart Memo Buffer" temporary; MemoCode: Code[10]): Text
var
GenericChartMemoEditor: Page "Generic Chart Memo Editor";
begin
exit(GenericChartMemoEditor.AssistEdit(TempGenericChartMemoBuf, MemoCode))
end;
local procedure BuildMultilanguageText(var TempGenericChartCaptionsBuf: Record "Generic Chart Captions Buffer" temporary; CaptionCode: Code[10]; var MultilanguageText: DotNet BusinessChartMultiLanguageText)
var
Language: Codeunit Language;
LanguageId: Integer;
begin
MultilanguageText := MultilanguageText.BusinessChartMultiLanguageText();
TempGenericChartCaptionsBuf.SetRange(Code, CaptionCode);
if TempGenericChartCaptionsBuf.FindSet() then
repeat
LanguageId := Language.GetLanguageId(TempGenericChartCaptionsBuf."Language Code");
if LanguageId <> 0 then
MultilanguageText.SetText(LanguageId, TempGenericChartCaptionsBuf.Caption);
until TempGenericChartCaptionsBuf.Next() = 0;
TempGenericChartCaptionsBuf.SetRange(Code)
end;
local procedure BuildCaptionBuf(var TempGenericChartCaptionsBuf: Record "Generic Chart Captions Buffer" temporary; CaptionCode: Code[10]; MultilanguageText: DotNet BusinessChartMultiLanguageText)
var
Language: Codeunit Language;
LanguageCode: Code[10];
Index: Integer;
begin
TempGenericChartCaptionsBuf.SetRange(Code, CaptionCode);
TempGenericChartCaptionsBuf.DeleteAll();
TempGenericChartCaptionsBuf.Code := CaptionCode;
for Index := 0 to MultilanguageText.Count - 1 do begin
LanguageCode := Language.GetLanguageCode(MultilanguageText.GetWindowsLanguageIdAt(Index));
if LanguageCode <> '' then begin
TempGenericChartCaptionsBuf."Language Code" := LanguageCode;
TempGenericChartCaptionsBuf.Caption := MultilanguageText.GetTextAt(Index);
if TempGenericChartCaptionsBuf.Insert() then;
end;
end;
TempGenericChartCaptionsBuf.SetRange(Code)
end;
local procedure BuildMemoMultilanguageText(var TempGenericChartMemoBuf: Record "Generic Chart Memo Buffer" temporary; MemoCode: Code[10]; var MultilanguageText: DotNet BusinessChartMultiLanguageText)
var
Language: Codeunit Language;
LanguageId: Integer;
begin
MultilanguageText := MultilanguageText.BusinessChartMultiLanguageText();
TempGenericChartMemoBuf.SetRange(Code, MemoCode);
if TempGenericChartMemoBuf.FindSet() then
repeat
Language.GetLanguageId(TempGenericChartMemoBuf."Language Code");
if LanguageId <> 0 then
MultilanguageText.SetText(LanguageId, TempGenericChartMemoBuf.GetMemoText());
until TempGenericChartMemoBuf.Next() = 0;
TempGenericChartMemoBuf.SetRange(Code)
end;
local procedure BuildMemoBuf(var TempGenericChartMemoBuf: Record "Generic Chart Memo Buffer" temporary; MemoCode: Code[10]; MultilanguageText: DotNet BusinessChartMultiLanguageText)
var
Language: Codeunit Language;
LanguageCode: Code[10];
Index: Integer;
begin
TempGenericChartMemoBuf.SetRange(Code, MemoCode);
TempGenericChartMemoBuf.DeleteAll();
TempGenericChartMemoBuf.Code := MemoCode;
for Index := 0 to MultilanguageText.Count - 1 do begin
LanguageCode := Language.GetLanguageCode(MultilanguageText.GetWindowsLanguageIdAt(Index));
if LanguageCode <> '' then begin
TempGenericChartMemoBuf."Language Code" := LanguageCode;
TempGenericChartMemoBuf.SetMemoText(MultilanguageText.GetTextAt(Index));
if TempGenericChartMemoBuf.Insert() then;
end;
end;
TempGenericChartMemoBuf.SetRange(Code);
end;
procedure GetUserLanguage(): Code[10]
var
Language: Codeunit Language;
begin
exit(Language.GetUserLanguageCode())
end;
procedure DescriptionCode(): Code[10]
begin
exit(DescriptionTok)
end;
procedure XAxisTitleCode(): Code[10]
begin
exit(XAxisTitleTok)
end;
procedure YAxisTitleCode(): Code[10]
begin
exit(YAxisTitleTok)
end;
local procedure ZAxisTitleCode(): Code[10]
begin
exit(ZAxisTitleTok)
end;
procedure XAxisCaptionCode(): Code[10]
begin
exit(XAxisCaptionTok)
end;
procedure ZAxisCaptionCode(): Code[10]
begin
exit(ZAxisCaptionTok)
end;
procedure RequiredMeasureCode(): Code[10]
begin
exit(RequiredTok)
end;
procedure OptionalMeasure1Code(): Code[10]
begin
exit(Optional1Tok)
end;
procedure OptionalMeasure2Code(): Code[10]
begin
exit(Optional2Tok)
end;
procedure OptionalMeasure3Code(): Code[10]
begin
exit(Optional3Tok)
end;
procedure OptionalMeasure4Code(): Code[10]
begin
exit(Optional4Tok)
end;
procedure OptionalMeasure5Code(): Code[10]
begin
exit(Optional5Tok)
end;
[EventSubscriber(ObjectType::Codeunit, Codeunit::"System Action Triggers", 'CustomizeChart', '', false, false)]
local procedure CustomizeChart(var TempChart: Record Chart temporary; var LookupOK: Boolean)
var
GenericChartMgt: Codeunit "Generic Chart Mgt";
begin
LookupOK := GenericChartMgt.ChartCustomization(TempChart)
end;
}