TAChart: Extract TBroadcaster from TCustomChartSource

* Move TBroadcaster and TListener to TAChartUtils

git-svn-id: trunk@24466 -
This commit is contained in:
ask 2010-04-06 12:27:20 +00:00
parent 9b01c35ba3
commit cd0c7d799e
3 changed files with 91 additions and 73 deletions

View File

@ -42,6 +42,7 @@ const
type
EChartError = class(Exception);
EChartIntervalError = class(EChartError);
EListenerError = class(EChartError);
TDoublePoint = record
X, Y: Double;
@ -139,6 +140,28 @@ type
property Index: Integer read GetIndex write SetIndex;
end;
{ TListener }
TListener = class
private
FIsListening: Boolean;
public
procedure Forget; virtual;
procedure Notify; virtual; abstract;
property IsListening: Boolean read FIsListening;
end;
{ TBroadcaster }
TBroadcaster = class(TFPList)
public
destructor Destroy; override;
public
procedure Broadcast;
procedure Subscribe(AListener: TListener);
procedure Unsubscribe(AListener: TListener);
end;
const
// 0-value, 1-percent, 2-label, 3-total, 4-xvalue
SERIES_MARK_FORMATS: array [TSeriesMarksStyle] of String = (
@ -703,4 +726,53 @@ begin
FOnChange := AValue;
end;
{ TListener }
procedure TListener.Forget;
begin
FIsListening := false;
end;
{ TBroadcaster }
procedure TBroadcaster.Broadcast;
var
i: Integer;
begin
for i := 0 to Count - 1 do
TListener(Items[i]).Notify;
end;
destructor TBroadcaster.Destroy;
var
i: Integer;
begin
for i := 0 to Count - 1 do
TListener(Items[i]).Forget;
inherited Destroy;
end;
procedure TBroadcaster.Subscribe(AListener: TListener);
begin
if AListener.IsListening then
raise EListenerError.Create('Listener subscribed twice');
if IndexOf(AListener) >= 0 then
raise EListenerError.Create('Duplicate listener');
AListener.FIsListening := true;
Add(AListener);
end;
procedure TBroadcaster.Unsubscribe(AListener: TListener);
var
i: Integer;
begin
if not AListener.IsListening then
raise EListenerError.Create('Listener not subscribed');
AListener.FIsListening := false;
i := IndexOf(AListener);
if i < 0 then
raise EListenerError.Create('Listener not found');
Delete(i);
end;
end.

View File

@ -96,12 +96,12 @@ type
procedure AfterDraw; override;
procedure BeforeDraw; override;
function ColorOrDefault(AColor: TColor; ADefault: TColor = clTAColor): TColor;
procedure GetBounds(out ABounds: TDoubleRect); override;
function GetGraphPoint(AIndex: Integer): TDoublePoint;
function GetGraphPointX(AIndex: Integer): Double; inline;
function GetGraphPointY(AIndex: Integer): Double; inline;
function GetSeriesColor: TColor; virtual;
function GetXMaxVal: Integer;
procedure GetBounds(out ABounds: TDoubleRect); override;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
@ -379,7 +379,7 @@ begin
FListener := TChartSeriesListener.Create(Self);
FBuiltinSource := TListChartSource.Create(Self);
FBuiltinSource.Name := BUILTIN_SOURCE_NAME;
FBuiltinSource.Subscribe(FListener);
FBuiltinSource.Broadcaster.Subscribe(FListener);
FMarks := TChartMarks.Create(FChart);
end;
@ -391,7 +391,7 @@ end;
destructor TChartSeries.Destroy;
begin
if FListener.IsListening then
Source.Unsubscribe(FListener);
Source.Broadcaster.Unsubscribe(FListener);
FBuiltinSource.Free;
FMarks.Free;
FListener.Free;
@ -553,9 +553,9 @@ procedure TChartSeries.SetSource(AValue: TCustomChartSource);
begin
if FSource = AValue then exit;
if FListener.IsListening then
Source.Unsubscribe(FListener);
Source.Broadcaster.Unsubscribe(FListener);
FSource := AValue;
Source.Subscribe(FListener);
Source.Broadcaster.Subscribe(FListener);
UpdateParentChart;
end;

View File

@ -26,7 +26,6 @@ uses
type
EEditableSourceRequired = class(EChartError);
EListenerError = class(EChartError);
TChartDataItem = record
X, Y: Double;
@ -35,24 +34,12 @@ type
end;
PChartDataItem = ^TChartDataItem;
{ TListener }
TListener = class
private
FIsListening: Boolean;
public
procedure Forget; virtual;
procedure Notify; virtual; abstract;
property IsListening: Boolean read FIsListening;
end;
{ TCustomChartSource }
TCustomChartSource = class(TComponent)
private
FListeners: array of TListener;
FBroadcaster: TBroadcaster;
FUpdateCount: Integer;
function FindListener(AListener: TListener): Integer;
protected
FExtent: TDoubleRect;
FExtentIsValid: Boolean;
@ -63,6 +50,7 @@ type
procedure InvalidateCaches;
procedure Notify;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
public
procedure AfterDraw; virtual;
@ -70,8 +58,6 @@ type
procedure BeginUpdate;
procedure EndUpdate;
function IsUpdating: Boolean; inline;
procedure Subscribe(AListener: TListener);
procedure Unsubscribe(AListener: TListener);
public
function Extent: TDoubleRect; virtual;
function FormatItem(const AFormat: String; AIndex: Integer): String;
@ -79,6 +65,7 @@ type
function XOfMax: Double;
function XOfMin: Double;
property Broadcaster: TBroadcaster read FBroadcaster;
property Count: Integer read GetCount;
property Item[AIndex: Integer]: PChartDataItem read GetItem; default;
end;
@ -252,14 +239,16 @@ begin
Inc(FUpdateCount);
end;
destructor TCustomChartSource.Destroy;
var
i: Integer;
constructor TCustomChartSource.Create(AOwner: TComponent);
begin
for i := 0 to High(FListeners) do
FListeners[i].Forget;
FListeners := nil;
inherited Destroy;
inherited Create(AOwner);
FBroadcaster := TBroadcaster.Create;
end;
destructor TCustomChartSource.Destroy;
begin
FBroadcaster.Free;
inherited;
end;
procedure TCustomChartSource.EndUpdate;
@ -283,13 +272,6 @@ begin
Result := FExtent;
end;
function TCustomChartSource.FindListener(AListener: TListener): Integer;
begin
for Result := 0 to High(FListeners) do
if FListeners[Result] = AListener then exit;
Result := -1;
end;
function TCustomChartSource.FormatItem(
const AFormat: String; AIndex: Integer): String;
const
@ -319,38 +301,9 @@ begin
end;
procedure TCustomChartSource.Notify;
var
i: Integer;
begin
if IsUpdating then exit;
for i := 0 to High(FListeners) do
FListeners[i].Notify;
end;
procedure TCustomChartSource.Subscribe(AListener: TListener);
begin
if AListener.IsListening then
raise EListenerError.Create('Listener subscribed twice');
if FindListener(AListener) >= 0 then
raise EListenerError.Create('Duplicate listener');
AListener.FIsListening := true;
SetLength(FListeners, Length(FListeners) + 1);
FListeners[High(FListeners)] := AListener;
end;
procedure TCustomChartSource.Unsubscribe(AListener: TListener);
var
i, j: Integer;
begin
if not AListener.IsListening then
raise EListenerError.Create('Listener not subscribed');
AListener.FIsListening := false;
j := FindListener(AListener);
if j < 0 then
raise EListenerError.Create('Listener not found');
for i := j to High(FListeners) - 1 do
FListeners[i] := FListeners[i + 1];
SetLength(FListeners, Length(FListeners) - 1);
if not IsUpdating then
FBroadcaster.Broadcast;
end;
function TCustomChartSource.ValuesTotal: Double;
@ -774,13 +727,6 @@ begin
Notify;
end;
{ TListener }
procedure TListener.Forget;
begin
FIsListening := false;
end;
{ TUserDefinedChartSource }
function TUserDefinedChartSource.GetCount: Integer;