[Qtcsharp-patches] Bugtussle/src/static/kylix QtClassesUtils.pas,1.1,1.2
Status: Inactive
Brought to you by:
manyoso
|
From: Andreas H. <ah...@us...> - 2004-11-09 20:05:47
|
Update of /cvsroot/qtcsharp/Bugtussle/src/static/kylix In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv21422/src/static/kylix Modified Files: QtClassesUtils.pas Log Message: Update Index: QtClassesUtils.pas =================================================================== RCS file: /cvsroot/qtcsharp/Bugtussle/src/static/kylix/QtClassesUtils.pas,v retrieving revision 1.1 retrieving revision 1.2 diff -C2 -d -r1.1 -r1.2 *** QtClassesUtils.pas 15 Aug 2004 20:46:00 -0000 1.1 --- QtClassesUtils.pas 9 Nov 2004 20:05:36 -0000 1.2 *************** *** 1,2 **** --- 1,32 ---- + { + Type Casts: + It is not possible to typecast a Qt Delphi object to another Qt Delphi object + when the Qt object handle is not created by Delphi (ObjectLookup) because in + this case the returned value is a Qt Delphi object of the return type and a + direct typecast with a following call to a virual/dynamic function will raise + an AV due to a wrong VMT. So we must use the QtCast() functions for this. + + If a Qt created object is returned the Delphi object that is created has the + return-type type. If this is not the same as the actual object you must cast + to the actual type with the QtCast() function. It simply creates a new Delphi + instance with the same handle (that is not registered to the ObjectLookup- + table) and adds the instance to a CastConnection list, which is shared by the + "old" and "new" Delphi object. At this time two Delphi instances exist in + memory and both refere to the same Qt object. This is repeated for each type + cast to another class type. If the type cast is to a type that has already + been done or is a base class of another type cast's type, the most specialized + type is returned which makes type casts faster. + + When you destroy one of these cast-connected objects all other connected + objects will be destroyed, too. This means that if you keep at least one + reference to one of the casted objects, you can discard the other ones. + + + Signals/Slots: + Delphi signals and slots must be registered in the QObjectBase.GetSignalSlot() + method. + + } + unit QtClassesUtils; *************** *** 4,260 **** uses ! QtLibrary; type ! TQtObjectBase = class(TObject) private protected FHandle: Pointer; ! procedure DeleteHandle; virtual; procedure OverrideMethods; virtual; public - constructor CreateHandle(AHandle: TImportLibraryBase); destructor Destroy; override; end; ! PHashItemCollision = ^THashItemCollision; ! THashItemCollision = record ! Key, Value: TObject; ! Next: PHashItemCollision; ! end; ! ! THashItem = record ! Empty: Boolean; ! Key, Value: TObject; ! Collision: PHashItemCollision; end; ! // THashtable is a small hash table that is not really good, but better than ! // a search in a TList. ! THashtable = class(TObject) private ! FDelta: Integer; ! FItems: array of THashItem; ! function GetItems(AKey: TObject): TObject; protected ! function Hashing(AKey: TObject): Cardinal; public ! constructor Create(ADelta: Integer = 512); ! destructor Destroy; override; ! procedure Add(AKey, AValue: TObject); ! function Remove(AKey: TObject): Boolean; ! property Items[AKey: TObject]: TObject read GetItems; default; end; ! type ! TQtObjectBaseClass = class of TQtObjectBase; ! function QtCast(Handle: TImportLibraryBase; ToClass: TQtObjectBaseClass): Pointer;{TQtObjectBase} overload; ! function QtCast(Obj: TQtObjectBase; ToClass: TQtObjectBaseClass): Pointer;{TQtObjectBase} overload; implementation var ! ObjectLookup: THashtable; type ! IQtCastHandle = interface ! function get: Pointer; end; ! function QtCast(Handle: TImportLibraryBase; ToClass: TQtObjectBaseClass): Pointer;{TQtObjectBase} begin ! Result := TQtObjectBase(ObjectLookup[Handle]); ! if Result = nil then ! Result := ToClass.CreateHandle(Handle); end; ! function QtCast(Obj: TQtObjectBase; ToClass: TQtObjectBaseClass): Pointer;{TQtObjectBase} begin ! Result := TQtObjectBase(ObjectLookup[Obj.FHandle]); ! if Result = nil then ! Result := ToClass.CreateHandle(Obj.FHandle); end; ! function QtCastIntf(Obj: TImportLibraryBase; ToClass: TQtObjectBaseClass): IQtCastHandle; begin ! //Result := TQtCastHandle.Create(QtCast(Obj, ToClass)); ! Result := nil; end; ! { TQtObjectBase } ! constructor TQtObjectBase.CreateHandle(AHandle: TImportLibraryBase); begin ! inherited Create; ! FHandle := AHandle; ! ObjectLookup.Add(AHandle, Self); ! OverrideMethods; end; ! destructor TQtObjectBase.Destroy; ! var ! H: Pointer; begin ! H := FHandle; ! try ! DeleteHandle; ! finally ! ObjectLookup.Remove(TObject(FHandle)); ! end; ! inherited Destroy; end; ! procedure TQtObjectBase.DeleteHandle; begin ! // do nothing end; ! procedure TQtObjectBase.OverrideMethods; begin end; ! { THashtable } ! constructor THashtable.Create(ADelta: Integer); begin ! inherited Create; ! FDelta := ADelta; ! if FDelta < 256 then ! FDelta := 256; ! SetLength(FItems, FDelta); end; ! destructor THashtable.Destroy; var i: Integer; - P, N: PHashItemCollision; begin ! for i := 0 to High(FItems) do begin ! P := FItems[i].Collision; ! // release collision list ! while P <> nil do ! begin ! N := P.Next; ! Dispose(P); ! P := N; ! end; end; end; ! function THashtable.Hashing(AKey: TObject): Cardinal; begin ! Result := (Cardinal(AKey) shr 2) mod Cardinal(Length(FItems)); end; ! procedure THashtable.Add(AKey, AValue: TObject); var ! Index: Cardinal; ! P: PHashItemCollision; begin ! Index := Hashing(AKey); ! with FItems[Index] do ! begin ! if Empty then ! begin ! Key := AKey; ! Value := AValue; ! Empty := False; ! end ! else begin ! New(P); ! P.Key := AKey; ! P.Value := AValue; ! P.Next := Collision; ! Collision := P; end; end; end; ! function THashtable.GetItems(AKey: TObject): TObject; var ! P: PHashItemCollision; ! Index: Cardinal; begin ! Result := nil; ! Index := Hashing(AKey); ! with FItems[Index] do begin ! if Key = AKey then ! Result := Value ! else begin ! // search in collision list ! P := Collision; ! while P <> nil do begin ! if P.Key = AKey then ! begin ! Result := Value; ! Break; ! end; ! P := P.Next; end; end; end; end; ! function THashtable.Remove(AKey: TObject): Boolean; var ! P, N: PHashItemCollision; ! Index: Cardinal; begin ! Result := False; ! Index := Hashing(AKey); ! with FItems[Index] do begin ! if Key = AKey then ! begin ! Result := True; ! if Collision <> nil then ! begin ! Key := Collision.Key; ! Value := Collision.Value; ! P := Collision.Next; ! Dispose(Collision); ! Collision := P; ! if Collision = nil then ! Empty := True; ! end; ! end ! else if Collision <> nil then ! begin ! P := Collision^.Next; ! if Collision.Key = AKey then begin Result := True; ! Dispose(Collision); ! Collision := P; ! end ! else ! begin ! N := Collision; ! while P <> nil do begin ! if P.Key = AKey then ! begin ! Result := True; ! N^.Next := P^.Next; ! Dispose(P); ! Break; ! end; ! N := P; ! P := P.Next; end; end; end; end; end; end. --- 34,585 ---- uses ! {$IFDEF MSWINDOWS} ! Windows, ! {$ENDIF MSWINDOWS} ! QtLibrary, Classes, Contnrs; type ! TCWrapperObjectBase = class; ! ! PCastConnection = ^TCastConnection; ! TCastConnection = record ! Instance: TCWrapperObjectBase; ! Next: PCastConnection; ! end; ! ! TCWrapperObjectBase = class(TObject) private + FCastConnection: PCastConnection; + FAutoDelete: Boolean; + FHandleMode: Integer; + + constructor CreateCastedHandle(AHandle: TImportLibraryBase); + constructor CreateCasted(Instance: TCWrapperObjectBase); protected FHandle: Pointer; ! procedure override_destructor; cdecl; ! ! procedure DeleteHandle(Handle: Pointer); virtual; abstract; procedure OverrideMethods; virtual; + + constructor CreateHandle(AHandle: TImportLibraryBase; AAutoDelete: Boolean = True); public destructor Destroy; override; end; + TSignalSlotList = class(TObject) + private + FList: TList; + protected + function Find(const XMember: string): Pointer; + public + constructor Create; + destructor Destroy; override; ! procedure AddSignal(Member: string; const Method); ! procedure AddSlot(Member: string; const Method: TMethod); end; ! TQObjectBase = class(TCWrapperObjectBase) private ! FSignalSlots: TSignalSlotList; ! function GetHandle: QObjectH; protected ! procedure InitHandle; virtual; ! procedure DeleteHandle(Handle: Pointer); override; ! procedure GetSignalSlot(List: TSignalSlotList); virtual; ! { This method is invoked by the constructor. Each decendant must add it's ! signals and slots in this method to the list. Otherwise the signals and ! slots are not usable through connect/disconnect. } public ! function className: string; ! function isA(const classname: string): Boolean; ! function inherits(const classname: string): Boolean; ! function signalsBlocked: Boolean; ! procedure blockSignals(b: Boolean); ! class function connect(sender: TQObjectBase; const signal: string; receiver: TQObjectBase; const member: string): Boolean; overload; ! class function disconnect(sender: TQObjectBase; const signal: string; receiver: TQObjectBase; const member: string): Boolean; overload; ! function connect(sender: TQObjectBase; const signal: string; const member: string): Boolean; overload; ! function disconnect(const signal: string = ''; receiver: TQObjectBase = nil; const member: string = ''): Boolean; overload; ! function disconnect(receiver: TQObjectBase; const member: string = ''): Boolean; overload; cdecl; ! ! property Handle: QObjectH read GetHandle; end; ! TCWrapperObjectBaseClass = class of TCWrapperObjectBase; ! IQtCastObject = interface ! function get: TCWrapperObjectBase; ! end; ! ! // QtCastIntf casts the @Handle to @ToClass and returns a autodeletion interface. ! // If the Handle is a Delphi Instance handle the autodelete mechanism is ! // deactivated. ! function QtCastIntf(ToClass: TCWrapperObjectBaseClass; Handle: TImportLibraryBase): IQtCastObject overload; ! ! // QtCast(handle) casts the @Handle to @ToClass. If the handle is a Delphi Instance ! // handle the Instance is returned otherwise a new Instance of ToClass is created ! // and returned. ! function QtCast(ToClass: TCWrapperObjectBaseClass; Handle: TImportLibraryBase): Pointer;{TCWrapperObjectBase} overload; ! ! // QtCast(instance) casts the @Instance to @ToClass. if @Instances is @ToClass ! // the Instance is returned. Otherwise the Instance is removed from the Delphi ! // Object Lookup list and connected to the new (created) Delphi Instance ! function QtCast(ToClass: TCWrapperObjectBaseClass; Instance: TCWrapperObjectBase): Pointer;{TCWrapperObjectBase} overload; implementation var ! ObjectLookup: TBucketList; ! IntfCastList: TList; ! LookupCritSect: TRTLCriticalSection; ! ! const ! // HandleMode ! HMODE_HANDLE = 0; ! HMODE_CASTEDHANDLE = 1; ! HMODE_CASTEDINSTANCE = 2; type ! TQtCastObject = class(TInterfacedObject, IQtCastObject) ! private ! FInstance: TCWrapperObjectBase; ! FAutoDeleteInstance: Boolean; ! public ! constructor Create(AInstance: TCWrapperObjectBase; AAutoDeleteInstance: Boolean); ! destructor Destroy; override; ! function get: TCWrapperObjectBase; end; ! { TQtCastObject } ! ! constructor TQtCastObject.Create(AInstance: TCWrapperObjectBase; AAutoDeleteInstance: Boolean); begin ! inherited Create; ! FInstance := AInstance; ! FAutoDeleteInstance := AAutoDeleteInstance; ! IntfCastList.Add(AInstance); end; ! destructor TQtCastObject.Destroy; begin ! if FAutoDeleteInstance then ! begin ! FInstance.FAutoDelete := False; // Do not delete the handle ! ! EnterCriticalSection(LookupCritSect); ! try ! if IntfCastList.IndexOf(FInstance) >= 0 then ! FInstance.Free; ! finally ! LeaveCriticalSection(LookupCritSect); ! end; ! end; end; ! function TQtCastObject.get: TCWrapperObjectBase; begin ! Result := FInstance; end; ! function GetMostSpecializedInstance(Handle: TImportLibraryBase): TCWrapperObjectBase; ! var ! P: PCastConnection; ! begin ! Result := nil; ! if (Handle <> nil) and ObjectLookup.Find(Handle, Pointer(Result)) then ! begin ! P := Result.FCastConnection; ! while P <> nil do ! begin ! if P.Instance.InheritsFrom(Result.ClassType) then ! Result := P.Instance; ! P := P.Next; ! end; ! end; ! end; ! function QtCast(ToClass: TCWrapperObjectBaseClass; Handle: TImportLibraryBase): Pointer;{TCWrapperObjectBase} begin ! if Handle <> nil then ! begin ! EnterCriticalSection(LookupCritSect); ! try ! Result := GetMostSpecializedInstance(Handle); ! if Result = nil then ! Result := ToClass.CreateCastedHandle(Handle); // does not destroy the handle on destruction ! finally ! LeaveCriticalSection(LookupCritSect); ! end; ! end ! else ! Result := nil; end; ! function QtCast(ToClass: TCWrapperObjectBaseClass; Instance: TCWrapperObjectBase): Pointer;{TCWrapperObjectBase} begin ! if Instance <> nil then ! begin ! if Instance is ToClass then ! Result := Instance ! else ! begin ! EnterCriticalSection(LookupCritSect); ! try ! Result := ToClass.CreateCasted(Instance); // does not destroy the handle on destruction ! finally ! LeaveCriticalSection(LookupCritSect); ! end; ! end; ! end ! else ! Result := nil; end; ! function QtCastIntf(ToClass: TCWrapperObjectBaseClass; Handle: TImportLibraryBase): IQtCastObject; ! var ! Instance: TCWrapperObjectBase; begin ! if Handle <> nil then ! begin ! EnterCriticalSection(LookupCritSect); ! try ! Instance := GetMostSpecializedInstance(Handle); ! if Instance <> nil then ! Result := TQtCastObject.Create(Instance, False) ! else ! Result := TQtCastObject.Create(QtCast(ToClass, Handle), True); ! finally ! LeaveCriticalSection(LookupCritSect); ! end; ! end ! else ! Result := nil; end; ! function MemberToCMember(const Member: string): string; begin + Result := Member; + {TODO implement } end; + { TSignalSlotList } ! type ! PSignalSlotItem = ^TSignalSlotItem; ! TSignalSlotItem = record ! Member: string; ! Method: TMethod; ! end; ! constructor TSignalSlotList.Create; begin ! FList := TList.Create; end; ! destructor TSignalSlotList.Destroy; ! begin ! FList.Free; ! end; ! ! procedure TSignalSlotList.AddSignal(Member: string; const Method); var + N: PSignalSlotItem; i: Integer; begin ! Member := '2' + MemberToCMember(Member); ! if Find(Member) = nil then begin ! New(N); ! N.Member := Member; ! N.Method := TMethod(Method); end; end; ! procedure TSignalSlotList.AddSlot(Member: string; const Method: TMethod); ! var ! N: PSignalSlotItem; ! i: Integer; begin ! Member := '1' + MemberToCMember(Member); ! if Find(Member) = nil then ! begin ! New(N); ! N.Member := Member; ! N.Method := TMethod(Method); ! FList.Add(N); ! end; end; ! function TSignalSlotList.Find(const XMember: string): Pointer; var ! i: Integer; begin ! Result := nil; ! for i := 0 to FList.Count - 1 do ! if PSignalSlotItem(FList[i]).Member = XMember then begin ! Result := FList[i]; ! Exit; end; + end; + + { TCWrapperObjectBase } + + constructor TCWrapperObjectBase.CreateHandle(AHandle: TImportLibraryBase; AAutoDelete: Boolean); + begin + inherited Create; + FHandleMode := HMODE_HANDLE; + FHandle := AHandle; + FAutoDelete := AAutoDelete; + ObjectLookup.Add(AHandle, Self); + OverrideMethods; + end; + + // Creates a Instance that does not own the handle (no auto delete) but registers + // the instance to the LookupObject list. + constructor TCWrapperObjectBase.CreateCastedHandle(AHandle: TImportLibraryBase); + begin + inherited Create; + FHandleMode := HMODE_CASTEDHANDLE; + FHandle := AHandle; + FAutoDelete := False; + ObjectLookup.Add(AHandle, Self); + end; + + // Create a Instance that does not own the handle but must be connected to the + // handle owner. + constructor TCWrapperObjectBase.CreateCasted(Instance: TCWrapperObjectBase); + var + P: PCastConnection; + begin + inherited Create; + FHandleMode := HMODE_CASTEDINSTANCE; + FHandle := Instance.FHandle; + FAutoDelete := False; // The original Instance destroys the handle. + + // Add to the CastConnection list. + if Instance.FCastConnection = nil then + begin + // Create the CastConnection list for the handle owner and add the owner + // as the first entry. + New(Instance.FCastConnection); + Instance.FCastConnection.Instance := Instance; + Instance.FCastConnection.Next := nil; end; + P := Instance.FCastConnection; + while P.Next <> nil do + P := P.Next; + New(P.Next); + P := P.Next; + P.Instance := Self; + P.Next := nil; + FCastConnection := Instance.FCastConnection; end; ! destructor TCWrapperObjectBase.Destroy; var ! P: PCastConnection; ! H: Pointer; begin ! IntfCastList.Remove(Self); ! if FHandleMode = HMODE_CASTEDINSTANCE then begin ! // The first item in the cast-connection list is the handle owner. ! if FCastConnection <> nil then begin ! P := FCastConnection; ! FCastConnection := nil; // prevent recursive destruction ! P.Instance.Free; ! end; ! end ! else ! begin ! // destroy other cast connected instances (does not destroy the handle) ! if FCastConnection <> nil then ! begin ! // remove the first item because it is this object (Instance = Self) ! P := FCastConnection.Next; ! Dispose(FCastConnection); ! FCastConnection := P; ! end; ! while FCastConnection <> nil do ! begin ! if FCastConnection.Instance.FCastConnection <> nil then begin ! FCastConnection.Instance.FCastConnection := nil; // prevent recursion ! FCastConnection.Instance.Free; end; + P := FCastConnection.Next; + Dispose(FCastConnection); + FCastConnection := P; + end; + end; + + H := FHandle; + if H <> nil then + begin + FHandle := nil; // prevent recursive destruction by override_destroy + try + if FAutoDelete then + DeleteHandle(H); + finally + if FHandleMode <> HMODE_CASTEDINSTANCE then // HMODE_HANDLE and HMODE_CASTEDHANDLE register themself + ObjectLookup.Remove(H); end; end; + inherited Destroy; end; ! procedure TCWrapperObjectBase.override_destructor; ! begin ! if FHandle <> nil then // the handle was not destroyed by DeleteHandle ! begin ! FAutoDelete := False; // already deleted ! Free; ! end; ! end; ! ! procedure TCWrapperObjectBase.OverrideMethods; ! begin ! // do nothing ! end; ! ! ! { TQObjectBase } ! ! procedure TQObjectBase.GetSignalSlot(List: TSignalSlotList); ! begin ! end; ! ! function TQObjectBase.GetHandle: QObjectH; ! begin ! Result := nil; ! if Self <> nil then ! Result := FHandle; ! end; ! ! procedure TQObjectBase.InitHandle; ! begin ! FSignalSlots := TSignalSlotList.Create; ! GetSignalSlot(FSignalSlots); ! end; ! ! procedure TQObjectBase.DeleteHandle(Handle: Pointer); ! begin ! try ! QObjectH(Handle).Delete; // "virtual ~QObject()" ! finally ! FSignalSlots.Free; ! end; ! end; ! ! procedure TQObjectBase.blockSignals(b: Boolean); ! begin ! Handle.blockSignals(b); ! end; ! ! function TQObjectBase.signalsBlocked: Boolean; ! begin ! Result := Handle.signalsBlocked; ! end; ! ! function TQObjectBase.className: string; var ! Data: Pointer; begin ! Result := Handle.className; ! EnterCriticalSection(LookupCritSect); ! try ! if (FHandleMode = HMODE_HANDLE) and ObjectLookup.Find(FHandle, Data) and ! (Data = Self) then ! Result := TObject(Self).ClassName; ! finally ! LeaveCriticalSection(LookupCritSect); ! end; ! end; ! ! function TQObjectBase.inherits(const classname: string): Boolean; ! var ! Data: Pointer; ! Parent: TClass; ! begin ! Result := Handle.inherits(classname); ! if not Result then begin ! EnterCriticalSection(LookupCritSect); ! try ! if (FHandleMode = HMODE_HANDLE) and ObjectLookup.Find(FHandle, Data) and ! (Data = Self) then begin Result := True; ! Parent := TObject(Self).ClassParent; ! while Parent <> nil do begin ! if Parent.ClassName = classname then ! Exit; ! Parent := Parent.ClassParent; end; end; + finally + LeaveCriticalSection(LookupCritSect); end; end; end; + function TQObjectBase.isA(const classname: string): Boolean; + begin + Result := Handle.isA(classname); + if not Result then + Result := TObject(Self).ClassName = classname; + end; + + function TQObjectBase.connect(sender: TQObjectBase; const signal, + member: string): Boolean; + begin + Result := connect(sender, signal, Self, member); + end; + + function TQObjectBase.disconnect(const signal: string; + receiver: TQObjectBase; const member: string): Boolean; + begin + Result := disconnect(Self, signal, receiver, member); + end; + + class function TQObjectBase.connect(sender: TQObjectBase; + const signal: string; receiver: TQObjectBase; + const member: string): Boolean; + begin + // MemberToCMember(signal) + // MemberToCMember(member) + end; + + function TQObjectBase.disconnect(receiver: TQObjectBase; + const member: string): Boolean; + begin + Result := Handle.disconnect(receiver.Handle, Member); + end; + + class function TQObjectBase.disconnect(sender: TQObjectBase; + const signal: string; receiver: TQObjectBase; + const member: string): Boolean; + begin + // MemberToCMember(signal) + // MemberToCMember(member) + end; + + + initialization + ObjectLookup := TBucketList.Create(bl256); + IntfCastList := TList.Create; + InitializeCriticalSection(LookupCritSect); + + finalization + DeleteCriticalSection(LookupCritSect); + IntfCastList.Free; + ObjectLookup.Free; + end. + |