mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-08-13 12:59:15 +02:00
* Added observer support
git-svn-id: trunk@22257 -
This commit is contained in:
parent
e40505a998
commit
43be53351e
@ -147,6 +147,51 @@ type
|
|||||||
EInvalidOperation = class(Exception);
|
EInvalidOperation = class(Exception);
|
||||||
TExceptionClass = Class of Exception;
|
TExceptionClass = Class of Exception;
|
||||||
|
|
||||||
|
{ ---------------------------------------------------------------------
|
||||||
|
Free Pascal Observer support
|
||||||
|
---------------------------------------------------------------------}
|
||||||
|
|
||||||
|
|
||||||
|
Const
|
||||||
|
BaseGUIDObserved = '{663C603C-3F3C-4CC5-823C-AC8079F979E5}';
|
||||||
|
BaseGUIDObserver = '{BC7376EA-199C-4C2A-8684-F4805F0691CA}';
|
||||||
|
|
||||||
|
GUIDObserved : TGUID = BaseGUIDObserved;
|
||||||
|
GUIDObserver : TGUID = BaseGUIDObserver;
|
||||||
|
|
||||||
|
// String is needed for testing
|
||||||
|
SGUIDObserver = BaseGUIDObserver;
|
||||||
|
SGUIDObserved = BaseGUIDObserved;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Type
|
||||||
|
// Notification operations :
|
||||||
|
// Observer has changed, is freed, item added to/deleted from list, custom event.
|
||||||
|
TFPObservedOperation = (ooChanged,ooFree,ooAddItem,ooDeleteItem,ooCustom);
|
||||||
|
{$INTERFACES CORBA}
|
||||||
|
|
||||||
|
{ IFPObserved }
|
||||||
|
|
||||||
|
IFPObserved = Interface [BaseGUIDObserved]
|
||||||
|
// attach a new observer
|
||||||
|
Procedure FPOAttachObserver(AObserver : TObject);
|
||||||
|
// Detach an observer
|
||||||
|
Procedure FPODetachObserver(AObserver : TObject);
|
||||||
|
// Notify all observers of a change.
|
||||||
|
Procedure FPONotifyObservers(ASender : TObject; AOperation : TFPObservedOperation; Data : Pointer);
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ IFPObserver }
|
||||||
|
|
||||||
|
IFPObserver = Interface [BaseGUIDObserver]
|
||||||
|
// Called by observed when observers are notified.
|
||||||
|
Procedure FPOObservedChanged(ASender : TObject; Operation : TFPObservedOperation; Data : Pointer);
|
||||||
|
end;
|
||||||
|
{$INTERFACES COM}
|
||||||
|
|
||||||
|
EObserver = Class(Exception);
|
||||||
|
|
||||||
{ Forward class declarations }
|
{ Forward class declarations }
|
||||||
|
|
||||||
TStream = class;
|
TStream = class;
|
||||||
@ -269,9 +314,10 @@ type
|
|||||||
property Current: Pointer read GetCurrent;
|
property Current: Pointer read GetCurrent;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TList = class(TObject)
|
TList = class(TObject,IFPObserved)
|
||||||
private
|
private
|
||||||
FList: TFPList;
|
FList: TFPList;
|
||||||
|
FObservers : TFPList;
|
||||||
procedure CopyMove (aList : TList);
|
procedure CopyMove (aList : TList);
|
||||||
procedure MergeMove (aList : TList);
|
procedure MergeMove (aList : TList);
|
||||||
procedure DoCopy(ListA, ListB : TList);
|
procedure DoCopy(ListA, ListB : TList);
|
||||||
@ -293,6 +339,9 @@ type
|
|||||||
public
|
public
|
||||||
constructor Create;
|
constructor Create;
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
Procedure FPOAttachObserver(AObserver : TObject);
|
||||||
|
Procedure FPODetachObserver(AObserver : TObject);
|
||||||
|
Procedure FPONotifyObservers(ASender : TObject; AOperation : TFPObservedOperation; Data : Pointer);
|
||||||
Procedure AddList(AList : TList);
|
Procedure AddList(AList : TList);
|
||||||
function Add(Item: Pointer): Integer;
|
function Add(Item: Pointer): Integer;
|
||||||
procedure Clear; virtual;
|
procedure Clear; virtual;
|
||||||
@ -390,14 +439,19 @@ type
|
|||||||
|
|
||||||
{$M+}
|
{$M+}
|
||||||
|
|
||||||
TPersistent = class(TObject)
|
TPersistent = class(TObject,IFPObserved)
|
||||||
private
|
private
|
||||||
|
FObservers : TFPList;
|
||||||
procedure AssignError(Source: TPersistent);
|
procedure AssignError(Source: TPersistent);
|
||||||
protected
|
protected
|
||||||
procedure AssignTo(Dest: TPersistent); virtual;
|
procedure AssignTo(Dest: TPersistent); virtual;
|
||||||
procedure DefineProperties(Filer: TFiler); virtual;
|
procedure DefineProperties(Filer: TFiler); virtual;
|
||||||
function GetOwner: TPersistent; dynamic;
|
function GetOwner: TPersistent; dynamic;
|
||||||
|
Procedure FPOAttachObserver(AObserver : TObject);
|
||||||
|
Procedure FPODetachObserver(AObserver : TObject);
|
||||||
|
Procedure FPONotifyObservers(ASender : TObject; AOperation : TFPObservedOperation; Data : Pointer);
|
||||||
public
|
public
|
||||||
|
Destructor Destroy; override;
|
||||||
procedure Assign(Source: TPersistent); virtual;
|
procedure Assign(Source: TPersistent); virtual;
|
||||||
function GetNamePath: string; virtual; {dynamic;}
|
function GetNamePath: string; virtual; {dynamic;}
|
||||||
end;
|
end;
|
||||||
|
@ -288,6 +288,7 @@ end;
|
|||||||
|
|
||||||
procedure TCollection.Update(Item: TCollectionItem);
|
procedure TCollection.Update(Item: TCollectionItem);
|
||||||
begin
|
begin
|
||||||
|
FPONotifyObservers(Self,ooChanged,Pointer(Item));
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -395,6 +396,12 @@ end;
|
|||||||
|
|
||||||
procedure TCollection.Notify(Item: TCollectionItem;Action: TCollectionNotification);
|
procedure TCollection.Notify(Item: TCollectionItem;Action: TCollectionNotification);
|
||||||
begin
|
begin
|
||||||
|
if Assigned(FObservers) then
|
||||||
|
Case Action of
|
||||||
|
cnAdded : FPONotifyObservers(Self,ooAddItem,Pointer(Item));
|
||||||
|
cnExtracting : FPONotifyObservers(Self,ooCustom,Pointer(Item));
|
||||||
|
cnDeleting : FPONotifyObservers(Self,ooDeleteItem,Pointer(Item));
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TCollection.Sort(Const Compare : TCollectionSortCompare);
|
procedure TCollection.Sort(Const Compare : TCollectionSortCompare);
|
||||||
|
@ -606,6 +606,12 @@ end;
|
|||||||
|
|
||||||
procedure TList.Notify(Ptr: Pointer; Action: TListNotification);
|
procedure TList.Notify(Ptr: Pointer; Action: TListNotification);
|
||||||
begin
|
begin
|
||||||
|
if Assigned(FObservers) then
|
||||||
|
Case ACtion of
|
||||||
|
lnAdded : FPONotifyObservers(Self,ooAddItem,Ptr);
|
||||||
|
lnExtracted : FPONotifyObservers(Self,ooCustom,Ptr);
|
||||||
|
lnDeleted : FPONotifyObservers(Self,ooDeleteItem,Ptr);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TList.GetCapacity: integer;
|
function TList.GetCapacity: integer;
|
||||||
@ -642,10 +648,61 @@ destructor TList.Destroy;
|
|||||||
begin
|
begin
|
||||||
If (Flist<>Nil) then
|
If (Flist<>Nil) then
|
||||||
Clear;
|
Clear;
|
||||||
|
If Assigned(FObservers) then
|
||||||
|
begin
|
||||||
|
FPONotifyObservers(Self,ooFree,Nil);
|
||||||
|
FreeAndNil(FObservers);
|
||||||
|
end;
|
||||||
FreeAndNil(FList);
|
FreeAndNil(FList);
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TList.FPOAttachObserver(AObserver: TObject);
|
||||||
|
|
||||||
|
Var
|
||||||
|
I : IFPObserver;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If Not AObserver.GetInterface(SGUIDObserver,I) then
|
||||||
|
Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
|
||||||
|
If not Assigned(FObservers) then
|
||||||
|
FObservers:=TFPList.Create;
|
||||||
|
FObservers.Add(AObserver);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TList.FPODetachObserver(AObserver: TObject);
|
||||||
|
Var
|
||||||
|
I : IFPObserver;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If Not AObserver.GetInterface(SGUIDObserver,I) then
|
||||||
|
Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
|
||||||
|
If Assigned(FObservers) then
|
||||||
|
begin
|
||||||
|
FObservers.Remove(AObserver);
|
||||||
|
If (FObservers.Count=0) then
|
||||||
|
FreeAndNil(FObservers);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TList.FPONotifyObservers(ASender: TObject;
|
||||||
|
AOperation: TFPObservedOperation; Data : Pointer);
|
||||||
|
|
||||||
|
Var
|
||||||
|
O : TObject;
|
||||||
|
I : Integer;
|
||||||
|
Obs : IFPObserver;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If Assigned(FObservers) then
|
||||||
|
For I:=FObservers.Count-1 downto 0 do
|
||||||
|
begin
|
||||||
|
O:=TObject(FObservers[i]);
|
||||||
|
If O.GetInterface(SGUIDObserver,Obs) then
|
||||||
|
Obs.FPOObservedChanged(Self,AOperation,Data);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function TList.Add(Item: Pointer): Integer;
|
function TList.Add(Item: Pointer): Integer;
|
||||||
begin
|
begin
|
||||||
Result := FList.Add(Item);
|
Result := FList.Add(Item);
|
||||||
@ -664,7 +721,7 @@ begin
|
|||||||
for I := 0 to AList.Count - 1 do
|
for I := 0 to AList.Count - 1 do
|
||||||
if AList[I] <> nil then
|
if AList[I] <> nil then
|
||||||
Notify(AList[I], lnAdded);
|
Notify(AList[I], lnAdded);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TList.Clear;
|
procedure TList.Clear;
|
||||||
|
|
||||||
@ -681,7 +738,8 @@ var P : pointer;
|
|||||||
begin
|
begin
|
||||||
P:=FList.Get(Index);
|
P:=FList.Get(Index);
|
||||||
FList.Delete(Index);
|
FList.Delete(Index);
|
||||||
if assigned(p) then Notify(p, lnDeleted);
|
if assigned(p) then
|
||||||
|
Notify(p, lnDeleted);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
class procedure TList.Error(const Msg: string; Data: PtrInt);
|
class procedure TList.Error(const Msg: string; Data: PtrInt);
|
||||||
@ -692,6 +750,7 @@ end;
|
|||||||
procedure TList.Exchange(Index1, Index2: Integer);
|
procedure TList.Exchange(Index1, Index2: Integer);
|
||||||
begin
|
begin
|
||||||
FList.Exchange(Index1, Index2);
|
FList.Exchange(Index1, Index2);
|
||||||
|
FPONotifyObservers(Self,ooChanged,Nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TList.Expand: TList;
|
function TList.Expand: TList;
|
||||||
|
@ -49,6 +49,60 @@ begin
|
|||||||
Result:=Nil;
|
Result:=Nil;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
destructor TPersistent.Destroy;
|
||||||
|
begin
|
||||||
|
If Assigned(FObservers) then
|
||||||
|
begin
|
||||||
|
FPONotifyObservers(Self,ooFree,Nil);
|
||||||
|
FreeAndNil(FObservers);
|
||||||
|
end;
|
||||||
|
inherited Destroy;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPersistent.FPOAttachObserver(AObserver: TObject);
|
||||||
|
Var
|
||||||
|
I : IFPObserver;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If Not AObserver.GetInterface(SGUIDObserver,I) then
|
||||||
|
Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
|
||||||
|
If not Assigned(FObservers) then
|
||||||
|
FObservers:=TFPList.Create;
|
||||||
|
FObservers.Add(AObserver);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPersistent.FPODetachObserver(AObserver: TObject);
|
||||||
|
Var
|
||||||
|
I : IFPObserver;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If Not AObserver.GetInterface(SGUIDObserver,I) then
|
||||||
|
Raise EObserver.CreateFmt(SErrNotObserver,[AObserver.ClassName]);
|
||||||
|
If Assigned(FObservers) then
|
||||||
|
begin
|
||||||
|
FObservers.Remove(AObserver);
|
||||||
|
If (FObservers.Count=0) then
|
||||||
|
FreeAndNil(FObservers);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TPersistent.FPONotifyObservers(ASender: TObject;
|
||||||
|
AOperation: TFPObservedOperation; Data : Pointer);
|
||||||
|
Var
|
||||||
|
O : TObject;
|
||||||
|
I : Integer;
|
||||||
|
Obs : IFPObserver;
|
||||||
|
|
||||||
|
begin
|
||||||
|
If Assigned(FObservers) then
|
||||||
|
For I:=FObservers.Count-1 downto 0 do
|
||||||
|
begin
|
||||||
|
O:=TObject(FObservers[i]);
|
||||||
|
If O.GetInterface(SGUIDObserver,Obs) then
|
||||||
|
Obs.FPOObservedChanged(Self,AOperation,Data);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TPersistent.Assign(Source: TPersistent);
|
procedure TPersistent.Assign(Source: TPersistent);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
@ -551,6 +551,7 @@ end;
|
|||||||
Procedure TStrings.SetUpdateState(Updating: Boolean);
|
Procedure TStrings.SetUpdateState(Updating: Boolean);
|
||||||
|
|
||||||
begin
|
begin
|
||||||
|
FPONotifyObservers(Self,ooChanged,Nil);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
@ -1030,8 +1031,11 @@ Procedure TStringList.Changed;
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
If (FUpdateCount=0) Then
|
If (FUpdateCount=0) Then
|
||||||
|
begin
|
||||||
If Assigned(FOnChange) then
|
If Assigned(FOnChange) then
|
||||||
FOnchange(Self);
|
FOnchange(Self);
|
||||||
|
FPONotifyObservers(Self,ooChanged,Nil);
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user