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