diff --git a/components/tachart/languages/tachartstrconsts.de.po b/components/tachart/languages/tachartstrconsts.de.po
index 86c4b38c28..e8aa939051 100644
--- a/components/tachart/languages/tachartstrconsts.de.po
+++ b/components/tachart/languages/tachartstrconsts.de.po
@@ -290,6 +290,10 @@ msgstr "Linear"
msgid "Line series"
msgstr "Linien-Diagramm"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr "Die Anzahl der Datenwerte im %s.DataPoints-String \"%s\" entspricht nicht der, die aufgrund von XCount und YCount erwartet wird."
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logarithmisch"
diff --git a/components/tachart/languages/tachartstrconsts.fi.po b/components/tachart/languages/tachartstrconsts.fi.po
index b6a2e29f8a..941769a8d9 100644
--- a/components/tachart/languages/tachartstrconsts.fi.po
+++ b/components/tachart/languages/tachartstrconsts.fi.po
@@ -278,6 +278,10 @@ msgstr "Lineaarinen"
msgid "Line series"
msgstr "Viivakuvaaja"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logaritminen"
diff --git a/components/tachart/languages/tachartstrconsts.fr.po b/components/tachart/languages/tachartstrconsts.fr.po
index 0d3bb23458..e386ba854f 100644
--- a/components/tachart/languages/tachartstrconsts.fr.po
+++ b/components/tachart/languages/tachartstrconsts.fr.po
@@ -288,6 +288,10 @@ msgstr "Linéaire"
msgid "Line series"
msgstr "Séries de lignes"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logarithmique"
diff --git a/components/tachart/languages/tachartstrconsts.hu.po b/components/tachart/languages/tachartstrconsts.hu.po
index 079e69b6d2..7b92b19cf4 100644
--- a/components/tachart/languages/tachartstrconsts.hu.po
+++ b/components/tachart/languages/tachartstrconsts.hu.po
@@ -288,6 +288,10 @@ msgstr "Lineáris"
msgid "Line series"
msgstr "Vonal"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logaritmikus"
diff --git a/components/tachart/languages/tachartstrconsts.lt.po b/components/tachart/languages/tachartstrconsts.lt.po
index db2a1dba84..1d0b8efcd6 100644
--- a/components/tachart/languages/tachartstrconsts.lt.po
+++ b/components/tachart/languages/tachartstrconsts.lt.po
@@ -289,6 +289,10 @@ msgstr "Tiesinė"
msgid "Line series"
msgstr "Linijų sekos"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logaritminė"
diff --git a/components/tachart/languages/tachartstrconsts.pl.po b/components/tachart/languages/tachartstrconsts.pl.po
index 652d49bf3c..2290c8fbd3 100644
--- a/components/tachart/languages/tachartstrconsts.pl.po
+++ b/components/tachart/languages/tachartstrconsts.pl.po
@@ -288,6 +288,10 @@ msgstr "Liniowy"
msgid "Line series"
msgstr ""
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logarytmiczny"
diff --git a/components/tachart/languages/tachartstrconsts.pot b/components/tachart/languages/tachartstrconsts.pot
index 3447d274d4..2539aa6343 100644
--- a/components/tachart/languages/tachartstrconsts.pot
+++ b/components/tachart/languages/tachartstrconsts.pot
@@ -278,6 +278,10 @@ msgstr ""
msgid "Line series"
msgstr ""
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr ""
diff --git a/components/tachart/languages/tachartstrconsts.pt_BR.po b/components/tachart/languages/tachartstrconsts.pt_BR.po
index 37429af2a3..7a67b7b49a 100644
--- a/components/tachart/languages/tachartstrconsts.pt_BR.po
+++ b/components/tachart/languages/tachartstrconsts.pt_BR.po
@@ -288,6 +288,10 @@ msgstr "Linear"
msgid "Line series"
msgstr "Série Linha"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logarítimo"
diff --git a/components/tachart/languages/tachartstrconsts.ru.po b/components/tachart/languages/tachartstrconsts.ru.po
index ae8cec5aac..605960b4ad 100644
--- a/components/tachart/languages/tachartstrconsts.ru.po
+++ b/components/tachart/languages/tachartstrconsts.ru.po
@@ -288,6 +288,10 @@ msgstr "Линейный масштаб"
msgid "Line series"
msgstr "График"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Логарифмический масштаб"
diff --git a/components/tachart/languages/tachartstrconsts.se.po b/components/tachart/languages/tachartstrconsts.se.po
index b160bfb898..4a99c49674 100644
--- a/components/tachart/languages/tachartstrconsts.se.po
+++ b/components/tachart/languages/tachartstrconsts.se.po
@@ -291,6 +291,10 @@ msgstr "Linjär"
msgid "Line series"
msgstr "Linjediagram"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Logaritmisk"
diff --git a/components/tachart/languages/tachartstrconsts.uk.po b/components/tachart/languages/tachartstrconsts.uk.po
index 2e77b764d3..4d065c3c20 100644
--- a/components/tachart/languages/tachartstrconsts.uk.po
+++ b/components/tachart/languages/tachartstrconsts.uk.po
@@ -291,6 +291,10 @@ msgstr "Лінійний масштаб"
msgid "Line series"
msgstr "Графік"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "Логарифмічний масштаб"
diff --git a/components/tachart/languages/tachartstrconsts.zh_CN.po b/components/tachart/languages/tachartstrconsts.zh_CN.po
index 781bd7f096..fabd190f12 100644
--- a/components/tachart/languages/tachartstrconsts.zh_CN.po
+++ b/components/tachart/languages/tachartstrconsts.zh_CN.po
@@ -289,6 +289,10 @@ msgstr "线性的(Linear)"
msgid "Line series"
msgstr "折线图系列"
+#: tachartstrconsts.rslistsourcestringformaterror
+msgid "The data value count in the %0:s.DataPoints string \"%1:s\" differs from what is expected from XCount and YCount."
+msgstr ""
+
#: tachartstrconsts.rslogarithmic
msgid "Logarithmic"
msgstr "对数的"
diff --git a/components/tachart/tachartstrconsts.pas b/components/tachart/tachartstrconsts.pas
index d7ccd5fc34..a618be911c 100644
--- a/components/tachart/tachartstrconsts.pas
+++ b/components/tachart/tachartstrconsts.pas
@@ -71,6 +71,9 @@ resourcestring
// Chart sources
rsSourceCountError = '%0:s requires a chart source with at least %1:d %2:s value(s) per data point.';
rsSourceCountError2 = 'This %0:s instance must have at least %1:d %2:s value(s) per data point.';
+ rsListSourceStringFormatError = 'The data value count in the %0:s.DataPoints '+
+ 'string "%1:s" differs from what is expected from XCount and YCount.';
+
// Transformations
tasAxisTransformsEditorTitle = 'Edit axis transformations';
diff --git a/components/tachart/tacustomsource.pas b/components/tachart/tacustomsource.pas
index 2782948b84..1658662ef3 100644
--- a/components/tachart/tacustomsource.pas
+++ b/components/tachart/tacustomsource.pas
@@ -73,6 +73,7 @@ type
EEditableSourceRequired = class(EChartError);
EXCountError = class(EChartError);
EYCountError = class(EChartError);
+ EListSourceStringFormatError = class(EChartError);
TChartValueText = record
FText: String;
diff --git a/components/tachart/tasources.pas b/components/tachart/tasources.pas
index 061a7332d6..b41fb8c2db 100644
--- a/components/tachart/tasources.pas
+++ b/components/tachart/tasources.pas
@@ -38,6 +38,7 @@ type
protected
function GetCount: Integer; override;
function GetItem(AIndex: Integer): PChartDataItem; override;
+ procedure Loaded; override;
procedure SetXCount(AValue: Cardinal); override;
procedure SetYCount(AValue: Cardinal); override;
public
@@ -258,7 +259,10 @@ type
TListChartSourceStrings = class(TStrings)
strict private
FSource: TListChartSource;
+ FLoadingCache: TStringList;
procedure Parse(AString: String; ADataItem: PChartDataItem);
+ private
+ procedure LoadingFinished;
protected
function Get(Index: Integer): String; override;
function GetCount: Integer; override;
@@ -266,6 +270,7 @@ type
procedure SetUpdateState(AUpdating: Boolean); override;
public
constructor Create(ASource: TListChartSource);
+ destructor Destroy; override;
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Insert(Index: Integer; const S: String); override;
@@ -284,7 +289,10 @@ end;
procedure TListChartSourceStrings.Clear;
begin
- FSource.Clear;
+ if not (csLoading in FSource.ComponentState) then
+ FSource.Clear
+ else
+ FreeAndNil(FLoadingCache);
end;
constructor TListChartSourceStrings.Create(ASource: TListChartSource);
@@ -293,6 +301,12 @@ begin
FSource := ASource;
end;
+destructor TListChartSourceStrings.Destroy;
+begin
+ inherited;
+ FLoadingCache.Free;
+end;
+
procedure TListChartSourceStrings.Delete(Index: Integer);
begin
FSource.Delete(Index);
@@ -306,29 +320,49 @@ begin
fs := DefaultFormatSettings;
fs.DecimalSeparator := '.';
with FSource[Index]^ do begin
- Result := Format('%g', [X], fs);
+ Result := '';
+ if FSource.XCount > 0 then
+ Result += Format('%g|', [X], fs);
for i := 0 to High(XList) do
- Result += Format('|%g', [XList[i]], fs);
+ Result += Format('%g|', [XList[i]], fs);
if FSource.YCount > 0 then
- Result += Format('|%g', [Y], fs);
+ Result += Format('%g|', [Y], fs);
for i := 0 to High(YList) do
- Result += Format('|%g', [YList[i]], fs);
- Result += Format('|%s|%s', [IntToColorHex(Color), Text]);
+ Result += Format('%g|', [YList[i]], fs);
+ Result += Format('%s|%s', [IntToColorHex(Color), Text]);
end;
end;
function TListChartSourceStrings.GetCount: Integer;
begin
- Result := FSource.Count;
+ if not (csLoading in FSource.ComponentState) then
+ Result := FSource.Count
+ else
+ if Assigned(FLoadingCache) then
+ Result := FLoadingCache.Count
+ else
+ Result := 0;
end;
procedure TListChartSourceStrings.Insert(Index: Integer; const S: String);
var
item: PChartDataItem;
begin
+ if csLoading in FSource.ComponentState then begin
+ if not Assigned(FLoadingCache) then
+ FLoadingCache := TStringList.Create;
+ FLoadingCache.Insert(Index, S);
+ exit;
+ end;
+
item := FSource.NewItem;
- FSource.FData.Insert(Index, item);
- Parse(S, item);
+ try
+ Parse(S, item);
+ FSource.FData.Insert(Index, item);
+ except
+ Dispose(item);
+ raise;
+ end;
FSource.UpdateCachesAfterAdd(item^.X, item^.Y);
end;
@@ -350,20 +384,33 @@ var
var
i: Integer;
begin
+ // Note: this method is called only when component loading is fully finished -
+ // so FSource.XCount and FSource.YCount are already properly estabilished
+
parts := Split(AString);
try
- if (FSource.XCount = 1) and (FSource.YCount + 3 < Cardinal(parts.Count)) then
- FSource.YCount := parts.Count - 3;
+ // There should be XCount + YCount .. XCount + YCount + 2 (for Color and Text)
+ // parts of the string
+ if (Cardinal(parts.Count) <> FSource.XCount + FSource.YCount + 2) then begin
+ if Length(AString) > 20 then AString := Copy(AString, 1, 20) + '...';
+ raise EListSourceStringFormatError.CreateFmt(
+ rsListSourceStringFormatError,
+ [IfThen(FSource.Name <> '', FSource.Name, FSource.ClassName), AString]);
+ end;
+
with ADataItem^ do begin
- X := StrToFloatOrDateTimeDef(NextPart);
- if FSource.XCount > 1 then
+ if FSource.XCount > 0 then begin
+ X := StrToFloatOrDateTimeDef(NextPart);
for i := 0 to High(XList) do
XList[i] := StrToFloatOrDateTimeDef(NextPart);
+ end else
+ X := NaN;
if FSource.YCount > 0 then begin
Y := StrToFloatOrDateTimeDef(NextPart);
for i := 0 to High(YList) do
YList[i] := StrToFloatOrDateTimeDef(NextPart);
- end;
+ end else
+ Y := NaN;
Color := StrToIntDef(NextPart, clTAColor);
Text := NextPart;
end;
@@ -384,10 +431,22 @@ end;
procedure TListChartSourceStrings.SetUpdateState(AUpdating: Boolean);
begin
- if AUpdating then
- FSource.BeginUpdate
- else
- FSource.EndUpdate;
+ if not (csLoading in FSource.ComponentState) then
+ if AUpdating then
+ FSource.BeginUpdate
+ else
+ FSource.EndUpdate;
+end;
+
+procedure TListChartSourceStrings.LoadingFinished;
+begin
+ // csLoading in FSource.ComponentState is already cleared
+ if Assigned(FLoadingCache) then
+ try
+ Assign(FLoadingCache);
+ finally
+ FreeAndNil(FLoadingCache);
+ end;
end;
{ TListChartSource }
@@ -781,6 +840,12 @@ begin
Notify;
end;
+procedure TListChartSource.Loaded;
+begin
+ inherited; // clears csLoading in ComponentState
+ (FDataPoints as TListChartSourceStrings).LoadingFinished;
+end;
+
{ TMWCRandomGenerator }
function TMWCRandomGenerator.Get: LongWord;
diff --git a/components/tachart/test/SourcesTest.pas b/components/tachart/test/SourcesTest.pas
index 42f60ea475..fdab6a903e 100644
--- a/components/tachart/test/SourcesTest.pas
+++ b/components/tachart/test/SourcesTest.pas
@@ -369,9 +369,9 @@ begin
oldSeparator := DefaultFormatSettings.DecimalSeparator;
try
DefaultFormatSettings.DecimalSeparator := ':';
- FSource.DataPoints.Add('3:5');
+ FSource.DataPoints.Add('3:5|?|?|');
AssertEquals(3.5, FSource[0]^.X);
- FSource.DataPoints[0] := '4.5';
+ FSource.DataPoints[0] := '4.5|?|?|';
AssertEquals(4.5, FSource[0]^.X);
finally
DefaultFormatSettings.DecimalSeparator := oldSeparator;
@@ -453,9 +453,81 @@ procedure TListSourceTest.Multi;
begin
FSource.Clear;
AssertEquals(1, FSource.YCount);
+ AssertEquals(1, FSource.YCount);
+
FSource.Add(1, 2);
FSource.YCount := 2;
AssertEquals([0], FSource[0]^.YList);
+
+ FSource.SetYList(0, [3]);
+ AssertEquals(3, FSource[0]^.YList[0]);
+
+ FSource.DataPoints.Add('1|2|3|?|t');
+ AssertEquals(1, FSource.XCount);
+ AssertEquals(2, FSource.YCount);
+ AssertEquals(1, FSource[1]^.X);
+ AssertEquals(2, FSource[1]^.Y);
+ AssertEquals(3, FSource[1]^.YList[0]);
+
+ try
+ FSource.DataPoints.Add('10|20|30|40|?|');
+ except
+ on E: Exception do
+ AssertTrue('Too many values', E is EListSourceStringFormatError);
+ end;
+ AssertEquals(2, FSource.Count);
+
+ try
+ FSource.DataPoints.Add('10|20|?|');
+ except
+ on E: Exception do
+ AssertTrue('Too few values', E is EListSourceStringFormatError);
+ end;
+ AssertEquals(2, FSource.Count);
+
+ try
+ FSource.DataPoints.Add('10|20|30|?');
+ except
+ on E: Exception do
+ AssertTrue('Text field missing', E is EListSourceStringFormatError);
+ end;
+ AssertEquals(2, FSource.Count);
+
+ try
+ FSource.DataPoints.Add('10|20|30|t');
+ except
+ on E: Exception do
+ AssertTrue('Color field missing', E is EListSourceStringFormatError);
+ end;
+ AssertEquals(2, FSource.Count);
+
+ try
+ FSource.AddXYList(4, []);
+ except
+ on E: Exception do
+ AssertTrue('Empty YList', E is TListChartSource.EYListEmptyError);
+ end;
+
+ FSource.Clear;
+ FSource.XCount := 2;
+ FSource.YCount := 3;
+ FSource.AddXListYList([1, 2], [3, 4, 5]);
+ AssertEquals(2, FSource.XCount);
+ AssertEquals(3, FSource.YCount);
+ AssertEquals(1, FSource[0]^.X);
+ AssertEquals(2, FSource[0]^.XList[0]);
+ AssertEquals(3, FSource[0]^.Y);
+ AssertEquals(4, FSource[0]^.YList[0]);
+ AssertEquals(5, FSource[0]^.YList[1]);
+
+ FSource.DataPoints.Add('10|20|30|40|50|?|t');
+ AssertEquals(10, FSource[1]^.X);
+ AssertEquals(20, FSource[1]^.XList[0]);
+ AssertEquals(30, FSource[1]^.Y);
+ AssertEquals(40, FSource[1]^.YList[0]);
+ AssertEquals(50, FSource[1]^.YList[1]);
+
+ (*
FSource.SetYList(0, [3, 4]);
AssertEquals('Extra items are chopped', [3], FSource[0]^.YList);
FSource.DataPoints.Add('1|2|3|4|?|t');
@@ -478,6 +550,7 @@ begin
except on E: Exception do
AssertTrue('Empty YList', E is TListChartSource.EYListEmptyError);
end;
+ *)
end;
procedure TListSourceTest.SetUp;
diff --git a/components/tachart/test/test.lpi b/components/tachart/test/test.lpi
index b0007fe33e..9ee1a8896b 100644
--- a/components/tachart/test/test.lpi
+++ b/components/tachart/test/test.lpi
@@ -24,9 +24,6 @@
-
-
-
@@ -85,7 +82,7 @@
-
+
@@ -98,6 +95,9 @@
+
+
+