TAChart: Fix TListChartSource.DataPoints streaming error. Issue #0035125, patch by Marcin Wiazowski. Update test program.

git-svn-id: trunk@60490 -
This commit is contained in:
wp 2019-02-24 21:27:39 +00:00
parent 97462a220d
commit cd2e076da1
17 changed files with 214 additions and 24 deletions

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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ė"

View File

@ -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"

View File

@ -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 ""

View File

@ -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"

View File

@ -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 "Логарифмический масштаб"

View File

@ -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"

View File

@ -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 "Логарифмічний масштаб"

View File

@ -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 "对数的"

View File

@ -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';

View File

@ -73,6 +73,7 @@ type
EEditableSourceRequired = class(EChartError);
EXCountError = class(EChartError);
EYCountError = class(EChartError);
EListSourceStringFormatError = class(EChartError);
TChartValueText = record
FText: String;

View File

@ -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;

View File

@ -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;

View File

@ -24,9 +24,6 @@
</BuildModes>
<PublishOptions>
<Version Value="2"/>
<IgnoreBinaries Value="False"/>
<IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
<ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
</PublishOptions>
<RunParams>
<FormatVersion Value="2"/>
@ -85,7 +82,7 @@
</CodeGeneration>
</CompilerOptions>
<Debugging>
<Exceptions Count="4">
<Exceptions Count="5">
<Item1>
<Name Value="EAbort"/>
</Item1>
@ -98,6 +95,9 @@
<Item4>
<Name Value="TListChartSource.EYListEmptyError"/>
</Item4>
<Item5>
<Name Value="EListSourceStringFormatError"/>
</Item5>
</Exceptions>
</Debugging>
</CONFIG>