mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-27 12:13:48 +02:00
669 lines
16 KiB
PHP
669 lines
16 KiB
PHP
{ TObservers }
|
|
|
|
function TObservers.CanObserve(const aID: Integer): Boolean;
|
|
begin
|
|
Result:=Assigned(FCanObserve) and FCanObserve(aID);
|
|
end;
|
|
|
|
procedure TObservers.AddObserver(const aID: Integer; const aIntf: IInterface);
|
|
|
|
var
|
|
I : integer;
|
|
P : PIDArray;
|
|
O : IObserver;
|
|
E : IEditLinkObserver;
|
|
|
|
begin
|
|
if not Supports(aIntf,IObserver,O) then
|
|
raise EObserverException.Create(SErrNotIObserverInterface);
|
|
if not CanObserve(aID) then
|
|
raise EObserverException.Create(SErrUnsupportedObserver);
|
|
P:=FList.GetIDArrayFromID(aId);
|
|
if P=Nil then
|
|
FList.AddInterface(aID,aIntf)
|
|
else
|
|
begin
|
|
if not Supports(aIntf,ISingleCastObserver) then
|
|
P^.Add(aIntf)
|
|
else
|
|
begin
|
|
if Supports(aIntf,IEditLinkObserver,E) and Not E.IsReadOnly then
|
|
begin
|
|
// There can be only one editing link observer.
|
|
For I:=0 to P^.Count-1 do
|
|
if Supports(P^.List[I],IEditLinkObserver,E) then
|
|
if not E.IsReadOnly then
|
|
Raise EObserverException.Create(SErrOnlyOneEditingObserverAllowed)
|
|
end;
|
|
P^.Add(aIntf)
|
|
end;
|
|
end;
|
|
if Assigned(FObserverAdded) then
|
|
FObserverAdded(aId,O);
|
|
end;
|
|
|
|
procedure TObservers.AddObserver(const aIDs: array of Integer; const aIntf: IInterface);
|
|
|
|
var
|
|
aID : integer;
|
|
|
|
begin
|
|
for aID in aIDs do
|
|
AddObserver(aId,aIntf);
|
|
end;
|
|
|
|
procedure TObservers.RemoveObserver(const aID: Integer; const aIntf: IInterface);
|
|
|
|
var
|
|
P : PIDArray;
|
|
|
|
begin
|
|
P:=FList.GetIDArrayFromID(aID);
|
|
if P=Nil then
|
|
exit;
|
|
P^.Remove(aIntf);
|
|
end;
|
|
|
|
procedure TObservers.RemoveObserver(const aIDs: array of Integer; const aIntf: IInterface);
|
|
|
|
var
|
|
aID : integer;
|
|
|
|
begin
|
|
for aID in aIDs do
|
|
RemoveObserver(aId,aIntf);
|
|
end;
|
|
|
|
function TObservers.IsObserving(const aID: Integer): Boolean;
|
|
|
|
var
|
|
O : IInterface;
|
|
|
|
begin
|
|
Result:=TryIsObserving(aID,O);
|
|
end;
|
|
|
|
function TObservers.TryIsObserving(const aID: Integer; out aIntf: IInterface): Boolean;
|
|
|
|
var
|
|
P : PIDArray;
|
|
|
|
begin
|
|
aIntf:=Nil;
|
|
Result:=False;
|
|
P:=FList.GetIDArrayFromID(aID);
|
|
if P=Nil then
|
|
exit;
|
|
aIntf:=P^.GetActive;
|
|
Result:=aIntf<>Nil;
|
|
end;
|
|
|
|
function TObservers.GetSingleCastObserver(const aID: Integer): IInterface;
|
|
|
|
var
|
|
P : PIDArray;
|
|
|
|
begin
|
|
Result:=Nil;
|
|
P:=FList.GetIDArrayFromID(aID);
|
|
if P<>Nil then
|
|
Result:=P^.GetSingleCast;
|
|
if Result=Nil then
|
|
raise EObserverException.CreateFmt(SErrObserverNoSinglecast, [aID]);
|
|
end;
|
|
|
|
function TObservers.GetMultiCastObserverArray(const aID: Integer): TIInterfaceArray;
|
|
|
|
var
|
|
aCount, I : Integer;
|
|
P : PIDArray;
|
|
O : IObserver;
|
|
|
|
begin
|
|
Result:=[];
|
|
P:=FList.GetIDArrayFromId(aId);
|
|
if P=Nil then
|
|
exit;
|
|
SetLength(Result,P^.Count);
|
|
aCount:=0;
|
|
for I:=0 to P^.Count-1 do
|
|
if Supports(P^.List[I],IMultiCastObserver,O) then
|
|
if O.Active then
|
|
begin
|
|
Result[aCount]:=O;
|
|
Inc(aCount);
|
|
end;
|
|
SetLength(Result,aCount);
|
|
if aCount=0 then
|
|
raise EObserverException.CreateFmt(SerrObserverNoMulticastFound, [aID]);
|
|
end;
|
|
|
|
function TObservers.GetMultiCastObserver(const aID: Integer): IInterfaceList;
|
|
|
|
Var
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
|
|
begin
|
|
Result:=TInterfaceList.Create;
|
|
IntfArray:=GetMultiCastObserverArray(aId);
|
|
For Intf in IntfArray do
|
|
Result.Add(Intf);
|
|
end;
|
|
|
|
{ TObservers.TIDArray }
|
|
|
|
procedure TObservers.TIDArray.Add(const aInterface: IInterface);
|
|
begin
|
|
if Count=Length(List) then
|
|
SetLength(List,Count+10);
|
|
List[Count]:=aInterface;
|
|
Inc(Count);
|
|
end;
|
|
|
|
procedure TObservers.TIDArray.Remove(const aInterface: IInterface);
|
|
|
|
var
|
|
I : Integer;
|
|
|
|
begin
|
|
I:=Count-1;
|
|
While (I>=0) and (List[i]<>aInterface) do
|
|
Dec(I);
|
|
if (I>=0) then
|
|
List[i]:=Nil;
|
|
end;
|
|
|
|
function TObservers.TIDArray.GetActive: IObserver;
|
|
|
|
var
|
|
I : integer;
|
|
|
|
begin
|
|
Result:=Nil;
|
|
I:=Count-1;
|
|
While (Result=Nil) and (I>=0) do
|
|
begin
|
|
if Supports(List[I],IObserver,Result) then
|
|
if Not Result.Active then
|
|
Result:=nil;
|
|
Dec(I);
|
|
end;
|
|
end;
|
|
|
|
function TObservers.TIDArray.GetSingleCast: ISingleCastObserver;
|
|
|
|
var
|
|
I : Integer;
|
|
E : IEditLinkObserver;
|
|
|
|
begin
|
|
Result:=Nil;
|
|
I:=Count-1;
|
|
While (Result=Nil) and (I>=0) do
|
|
begin
|
|
Result:=nil;
|
|
if Supports(List[I],ISingleCastObserver,Result) then
|
|
begin
|
|
if Not (Result.Active
|
|
and Supports(Result,IEditLinkObserver,E)
|
|
and not E.IsReadOnly) then
|
|
Result:=nil;
|
|
end;
|
|
Dec(I);
|
|
end;
|
|
end;
|
|
|
|
{ TObservers.TIDArrayList }
|
|
|
|
function TObservers.TIDArrayList.IndexOfID(aId: Integer): Integer;
|
|
begin
|
|
Result:=Count-1;
|
|
While (Result>=0) and (List[Result].ID<>aID) do
|
|
Dec(Result);
|
|
end;
|
|
|
|
function TObservers.TIDArrayList.AddID(aId: Integer): Integer;
|
|
begin
|
|
if Count=Length(List) then
|
|
SetLength(List,Count+10);
|
|
List[Count].ID:=aID;
|
|
Result:=Count;
|
|
Inc(Count);
|
|
end;
|
|
|
|
procedure TObservers.TIDArrayList.AddInterface(aID: integer;
|
|
aInterFace: IInterface);
|
|
|
|
var
|
|
Idx : Integer;
|
|
P : PIDarray;
|
|
|
|
begin
|
|
Idx:=AddID(aID);
|
|
P:=GetIDArray(Idx);
|
|
P^.Add(aInterface);
|
|
end;
|
|
|
|
function TObservers.TIDArrayList.GetIDArray(aIdx: Integer): PIDArray;
|
|
begin
|
|
Result:=@List[aIdx];
|
|
end;
|
|
|
|
function TObservers.TIDArrayList.GetIDArrayFromID(aId: Integer): PIDArray;
|
|
|
|
var
|
|
Idx : Integer;
|
|
|
|
begin
|
|
Result:=Nil;
|
|
Idx:=IndexOfID(aId);
|
|
if Idx<>-1 then
|
|
Result:=GetIDArray(Idx);
|
|
end;
|
|
|
|
{ TLinkObservers }
|
|
|
|
class function TLinkObservers.CheckObserving(const aObservers: TObservers; aID : Integer) : Integer;
|
|
|
|
begin
|
|
Result:=aID;
|
|
if Not aObservers.IsObserving(aID) then
|
|
raise EObserverException.CreateFmt(SErrObserverNotAvailable,[aID]);
|
|
end;
|
|
|
|
class function TLinkObservers.GetEditGridLink(const aObservers: TObservers): IEditGridLinkObserver;
|
|
|
|
var
|
|
aId: Integer;
|
|
|
|
begin
|
|
aId:=CheckObserving(aObservers, TObserverMapping.EditGridLinkID);
|
|
Result:=aObservers.GetSingleCastObserver(aID) as IEditGridLinkObserver;
|
|
end;
|
|
|
|
class function TLinkObservers.GetEditLink(const aObservers: TObservers): IEditLinkObserver;
|
|
|
|
var
|
|
aId: Integer;
|
|
|
|
begin
|
|
aId:=CheckObserving(aObservers,TObserverMapping.EditLinkID);
|
|
Result:=aObservers.GetSingleCastObserver(aID) as IEditLinkObserver;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditLinkUpdate(const aObservers: TObservers);
|
|
begin
|
|
GetEditLink(AObservers).Update;
|
|
end;
|
|
|
|
class function TLinkObservers.EditLinkTrackUpdate(const aObservers: TObservers): Boolean;
|
|
|
|
var
|
|
E : IEditLinkObserver;
|
|
T : IObserverTrack;
|
|
|
|
begin
|
|
Result:=False;
|
|
E:=GetEditLink(aObservers);
|
|
if Supports(E,IObserverTrack,T) then
|
|
if T.Track then
|
|
begin
|
|
Result:=true;
|
|
E.Update;
|
|
end;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditLinkReset(const aObservers: TObservers);
|
|
begin
|
|
GetEditLink(AObservers).Reset;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditLinkModified(aObservers: TObservers);
|
|
begin
|
|
GetEditLink(aObservers).Modified;
|
|
end;
|
|
|
|
class function TLinkObservers.EditLinkIsModified(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditLink(aObservers).IsModified;
|
|
end;
|
|
|
|
class function TLinkObservers.EditLinkIsValidChar(const aObservers: TObservers; aKey: Char): Boolean;
|
|
begin
|
|
Result:=GetEditLink(aObservers).IsValidChar(aKey);
|
|
end;
|
|
|
|
class function TLinkObservers.EditLinkIsEditing(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditLink(aObservers).IsEditing;
|
|
end;
|
|
|
|
class function TLinkObservers.EditLinkEdit(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditLink(aObservers).Edit;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditLinkSetIsReadOnly(const aObservers: TObservers; AValue: Boolean);
|
|
begin
|
|
GetEditLink(aObservers).IsReadOnly:=aValue;
|
|
end;
|
|
|
|
class function TLinkObservers.EditLinkIsReadOnly(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditLink(aObservers).IsReadOnly;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditGridLinkUpdate(const aObservers: TObservers);
|
|
begin
|
|
GetEditGridLink(aObservers).Update;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditGridLinkReset(const aObservers: TObservers);
|
|
begin
|
|
GetEditGridLink(aObservers).Reset;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditGridLinkModified(const aObservers: TObservers
|
|
);
|
|
begin
|
|
GetEditGridLink(aObservers).Modified;
|
|
end;
|
|
|
|
class function TLinkObservers.EditGridLinkIsModified(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditGridLink(aObservers).IsModified;
|
|
end;
|
|
|
|
class function TLinkObservers.EditGridLinkIsValidChar(const aObservers: TObservers; aKey: Char): Boolean;
|
|
begin
|
|
Result:=GetEditGridLink(aObservers).IsValidChar(aKey);
|
|
end;
|
|
|
|
class function TLinkObservers.EditGridLinkIsEditing(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditGridLink(aObservers).IsEditing
|
|
end;
|
|
|
|
class function TLinkObservers.EditGridLinkEdit(const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditGridLink(aObservers).Edit;
|
|
end;
|
|
|
|
class function TLinkObservers.EditGridLinkIsReadOnly(
|
|
const aObservers: TObservers): Boolean;
|
|
begin
|
|
Result:=GetEditGridLink(aObservers).IsReadOnly;
|
|
end;
|
|
|
|
class procedure TLinkObservers.EditGridLinkSetIsReadOnly(const aObservers: TObservers; aValue: Boolean);
|
|
|
|
begin
|
|
GetEditGridLink(aObservers).IsReadOnly:=aValue
|
|
end;
|
|
|
|
class procedure TLinkObservers.PositionLinkPosChanged(const aObservers: TObservers);
|
|
|
|
var
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
PL: IPositionLinkObserver;
|
|
PL170: IPositionLinkObserver170;
|
|
|
|
begin
|
|
if Not aObservers.IsObserving(TObserverMapping.PositionLinkID) then
|
|
Exit;
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.PositionLinkID);
|
|
for Intf in IntfArray do
|
|
begin
|
|
if Supports(Intf,IPositionLinkObserver,PL) then
|
|
PL.PosChanged;
|
|
if Supports(Intf,IPositionLinkObserver170,PL170) then
|
|
PL.PosChanged;
|
|
end;
|
|
end;
|
|
|
|
class procedure TLinkObservers.PositionLinkPosChanging(const aObservers: TObservers);
|
|
var
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
PL: IPositionLinkObserver;
|
|
PL170: IPositionLinkObserver170;
|
|
|
|
begin
|
|
if Not aObservers.IsObserving(TObserverMapping.PositionLinkID) then
|
|
Exit;
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.PositionLinkID);
|
|
for Intf in IntfArray do
|
|
begin
|
|
if Supports(Intf,IPositionLinkObserver,PL) then
|
|
PL.PosChanging;
|
|
if Supports(Intf,IPositionLinkObserver170,PL170) then
|
|
PL.PosChanging;
|
|
end;
|
|
end;
|
|
|
|
class procedure TLinkObservers.ListSelectionChanged(const aObservers: TObservers);
|
|
|
|
begin
|
|
if AObservers.IsObserving(TObserverMapping.EditLinkID) then
|
|
if not TLinkObservers.EditLinkIsEditing(aObservers) then
|
|
EditLinkReset(AObservers)
|
|
else
|
|
begin
|
|
EditLinkModified(aObservers);
|
|
EditLinkTrackUpdate(aObservers);
|
|
PositionLinkPosChanged(aObservers);
|
|
end;
|
|
if aObservers.IsObserving(TObserverMapping.ControlValueID) then
|
|
begin
|
|
ControlValueModified(aObservers);
|
|
ControlValueTrackUpdate(aObservers);
|
|
end;
|
|
if aObservers.IsObserving(TObserverMapping.PositionLinkID) then
|
|
PositionLinkPosChanged(aObservers);
|
|
end;
|
|
|
|
class procedure TLinkObservers.ControlValueUpdate(aObservers: TObservers);
|
|
|
|
var
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
O: IControlValueObserver;
|
|
|
|
begin
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.ControlValueID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IControlValueObserver,O) then
|
|
O.ValueUpdate;
|
|
end;
|
|
|
|
class procedure TLinkObservers.ControlValueModified(aObservers: TObservers);
|
|
|
|
var
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
O: IControlValueObserver;
|
|
|
|
begin
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.ControlValueID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IControlValueObserver,O) then
|
|
O.ValueModified;
|
|
end;
|
|
|
|
class function TLinkObservers.ControlValueTrackUpdate(const aObservers: TObservers): Boolean;
|
|
var
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
O: IControlValueObserver;
|
|
T : IObserverTrack;
|
|
|
|
begin
|
|
Result:=False;
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.ControlValueID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IControlValueObserver,O)
|
|
And Supports(O,IObserverTrack,T) then
|
|
if T.Track then
|
|
begin
|
|
Result:=true;
|
|
O.ValueUpdate;
|
|
end;
|
|
|
|
end;
|
|
|
|
class function TLinkObservers.AllowControlChange(const aObservers: TObservers): Boolean;
|
|
|
|
begin
|
|
if aObservers.IsObserving(TObserverMapping.EditLinkID) then
|
|
Result:=TLinkObservers.EditLinkEdit(aObservers)
|
|
else
|
|
Result := True;
|
|
end;
|
|
|
|
class procedure TLinkObservers.ControlChanged(const aObservers: TObservers);
|
|
|
|
begin
|
|
if (aObservers.IsObserving(TObserverMapping.EditLinkID))
|
|
and EditLinkEdit(aObservers) then
|
|
begin
|
|
EditLinkModified(aObservers);
|
|
EditLinkUpdate(aObservers);
|
|
end;
|
|
if aObservers.IsObserving(TObserverMapping.ControlValueID) then
|
|
begin
|
|
ControlValueModified(aObservers);
|
|
ControlValueUpdate(aObservers);
|
|
end;
|
|
if aObservers.IsObserving(TObserverMapping.PositionLinkID) then
|
|
PositionLinkPosChanged(aObservers);
|
|
end;
|
|
|
|
class function TLinkObservers.AllowControlChange(const aControl: TComponent): Boolean;
|
|
begin
|
|
AllowControlChange(aControl.Observers);
|
|
end;
|
|
|
|
class procedure TLinkObservers.ControlChanged(const aControl: TComponent);
|
|
begin
|
|
ControlChanged(aControl.Observers);
|
|
end;
|
|
|
|
class procedure TLinkObservers.IteratorLinkUpdateControlComponent(const aObservers: TObservers; aControl: TComponent);
|
|
var
|
|
O : IIteratorLinkObserver;
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
|
|
begin
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.IteratorLinkID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IIteratorLinkObserver,O) then
|
|
O.UpdateControlComponent(aControl);
|
|
end;
|
|
|
|
class procedure TLinkObservers.IteratorLinkStartFrom(const aObservers: TObservers; aPosition: Integer);
|
|
|
|
var
|
|
O : IIteratorLinkObserver;
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
|
|
begin
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.IteratorLinkID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IIteratorLinkObserver,O) then
|
|
O.StartFrom(aPosition);
|
|
end;
|
|
|
|
class function TLinkObservers.IteratorLinkMoveNext(const aObservers: TObservers): Boolean;
|
|
|
|
var
|
|
O : IIteratorLinkObserver;
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
|
|
begin
|
|
Result:=false;
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.IteratorLinkID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IIteratorLinkObserver,O) then
|
|
Result:=Result or O.MoveNext;
|
|
end;
|
|
|
|
class procedure TLinkObservers.IteratorLinkFinish(const aObservers: TObservers);
|
|
|
|
var
|
|
O : IIteratorLinkObserver;
|
|
IntfArray : TIInterfaceArray;
|
|
Intf : IInterface;
|
|
|
|
begin
|
|
IntfArray:=aObservers.GetMultiCastObserverArray(TObserverMapping.IteratorLinkID);
|
|
for Intf in IntfArray do
|
|
if Supports(Intf,IIteratorLinkObserver,O) then
|
|
O.Finish;
|
|
end;
|
|
|
|
{ TObserverMapping }
|
|
|
|
|
|
constructor TObserverMapping.Create;
|
|
begin
|
|
FList:=TStringList.Create;
|
|
// Don't use sorted, as it will change the IDs as more records are added
|
|
end;
|
|
|
|
destructor TObserverMapping.Destroy;
|
|
begin
|
|
FreeAndNil(FList);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class constructor TObserverMapping.Init;
|
|
begin
|
|
_Instance:=TObserverMapping.Create;
|
|
end;
|
|
|
|
class destructor TObserverMapping.Done;
|
|
begin
|
|
FreeAndNil(_Instance)
|
|
end;
|
|
|
|
class function TObserverMapping.GetObserverID(const aKey: string): Integer;
|
|
begin
|
|
Result:=Instance.List.Indexof(aKey);
|
|
if Result=-1 then
|
|
Result:=Instance.List.Add(aKey);
|
|
Result:=Result+MinPublicID;
|
|
end;
|
|
|
|
class procedure TObserverMapping.Clear;
|
|
begin
|
|
Instance.List.Clear;
|
|
end;
|
|
|
|
constructor ObservableMemberAttribute.Create(const aMemberName, aFramework: string; aTrack: Boolean);
|
|
begin
|
|
inherited Create;
|
|
FFramework := AFramework;
|
|
FMemberName := AMemberName;
|
|
FTrack := ATrack;
|
|
end;
|
|
|
|
constructor ObservableMemberAttribute.Create(const aMemberName: string; aTrack: Boolean);
|
|
begin
|
|
inherited Create;
|
|
FMemberName := AMemberName;
|
|
FTrack := ATrack;
|
|
end;
|
|
|
|
constructor ObservableMemberAttribute.Create(const aMemberName: string);
|
|
begin
|
|
inherited Create;
|
|
FMemberName := AMemberName;
|
|
end;
|
|
|
|
|