Componentes.Terceros.jvcl/official/3.36/design/JvDataProviderItemDesign.pas
2009-02-27 12:23:32 +00:00

987 lines
30 KiB
ObjectPascal

{-----------------------------------------------------------------------------
The contents of this file are subject to the Mozilla Public License
Version 1.1 (the "License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.mozilla.org/MPL/MPL-1.1.html
Software distributed under the License is distributed on an "AS IS" basis,
WITHOUT WARRANTY OF ANY KIND, either expressed or implied. See the License for
the specific language governing rights and limitations under the License.
The Original Code is: JvDataProviderItemDesign.pas, released on 2003-06-27.
The Initial Developers of the Original Code is Marcel Bestebroer.
Portions created by Marcel Bestebroer are Copyright (C) 2002 - 2003 Project JEDI
All Rights Reserved.
Contributor(s): -
You may retrieve the latest version of this file at the Project JEDI's JVCL home page,
located at http://jvcl.sourceforge.net
Known Issues:
-----------------------------------------------------------------------------}
// $Id: JvDataProviderItemDesign.pas 11891 2008-09-09 20:33:00Z obones $
unit JvDataProviderItemDesign;
{$I jvcl.inc}
interface
uses
Classes, SysUtils, TypInfo,
JvDataProvider, JvDataProviderIntf;
type
{ Default item designer for IJvDataItem and its supporting interfaces. This designer is able to handle any IJvDataItem
implementation and injects properties based on the interfaces it supports. This is accomplished by descendants of
this class (called Views in this context), which can not contain instance fields and who's published properties are
read and injected into the main designer class. Each descendant should be linked to its accompanying interface using
the RegisterDataItemIntfProp routine. Note that for the standard interfaces views have already been registered.
The downside is that you can only edit properties for registered interfaces. In some situations an interface could
be setup in multiple ways, ie. using a reference to a TAction or using a simple event, and the system is not able
to distinguish these two options (unless you provide a separate interface for each possibility and register a view
for it. See TBaseItemDsgn for the class that is used when the implementer of IJvDataItem is based on the
TExtensibleInterfacedPersistent class, providing a more flexible approach. }
TJvDataProviderItem = class(TPersistent)
private
FItem: IJvDataItem;
protected
function Item: IJvDataItem;
function GetOwner: TPersistent; override;
public
constructor Create(AnItem: IJvDataItem);
function GetNamePath: string; override;
end;
TJvDataProviderItemClass = class of TJvDataProviderItem;
{ Item designer based on implementations with TExtenisbleInterfacedPersistent as their base. Since these
implementations have access to the various implementers more directly, the property injection is handled slightly
different.
Instead of creating a single instance and linking it to the IJvDataItem implementation, we simply inject the
published properties from the implementers, and revert it when the item is deselected. The required amount of memory
is pre-calculated, too, to avoid possible access violations in case there are a lot of implementers and/or
properties to inject.
The downside is a decrease in performance, though the difference isn't much of an issue when in designing mode (who
really notices or cares about the difference between waiting 10ms or 100ms after selecting an item and seeing its
properties appear in the Object Inspector?).
}
TBaseItemDsgn = class (TExtensibleInterfacedPersistent)
private
function GetIsStoredProp(Index: Integer): Boolean;
{$IFDEF COMPILER10_UP}
function GetDynArrayProp(Index: Integer): Pointer;
procedure SetDynArrayProp(Index: Integer; Value: Pointer);
{$ENDIF COMPILER10_UP}
function GetFloatProp(Index: Integer): Extended;
procedure SetFloatProp(Index: Integer; Value: Extended);
function GetInt64Prop(Index: Integer): Int64;
procedure SetInt64Prop(Index: Integer; Value: Int64);
{$IFDEF COMPILER6_UP}
function GetInterfaceProp(Index: Integer): IInterface;
procedure SetInterfaceProp(Index: Integer; Value: IInterface);
{$ENDIF COMPILER6_UP}
function GetMethodProp(Index: Integer): TMethod;
procedure SetMethodProp(Index: Integer; Value: TMethod);
function GetOrdProp(Index: Integer): Longint;
procedure SetOrdProp(Index: Integer; Value: Longint);
function GetStrProp(Index: Integer): string;
procedure SetStrProp(Index: Integer; Value: string);
function GetVariantProp(Index: Integer): Variant;
procedure SetVariantProp(Index: Integer; Value: Variant);
function GetWideStrProp(Index: Integer): WideString;
procedure SetWideStrProp(Index: Integer; Value: WideString);
protected
procedure GetPropDataFromIndex(Index: Integer; out Instance: TObject; out Info: PPropInfo);
procedure InjectImplementers;
procedure RevertRTTI;
end;
// Free the item designer
procedure FreeItemDesigner(var designer: TPersistent);
// Retrieve an instance of the designer for the given item
function GetItemDesigner(AnItem: IJvDataItem): TPersistent;
// Register a property view for an IJvDataItem support interface
procedure RegisterDataItemIntfProp(const IID: TGUID; const PropClass: TJvDataProviderItemClass);
implementation
uses
Windows, ImgList,
JclSysUtils,
JvDsgnConsts, JvJCLUtils, JvVCL5Utils;
type
PPropData = ^TPropData;
TIntfItem = record
GUID: TGUID;
PropClass: TJvDataProviderItemClass;
end;
TIntfItems = array of TIntfItem;
var
GIntfPropReg: TIntfItems;
procedure FreeItemDesigner(var designer: TPersistent);
var
obj: TPersistent;
begin
obj := designer;
designer := nil;
if (obj <> nil) then
begin
if obj is TJvDataProviderItem then
// free the instance of TJvDataProviderItem we created in GetItemDesigner
obj.Free
else
// revert our changes to the RTTI
TBaseItemDsgn(obj).RevertRTTI;
end;
end;
function GetItemDesigner(AnItem: IJvDataItem): TPersistent;
var
impl: TObject;
begin
impl := AnItem.Implementer;
if (impl is TExtensibleInterfacedPersistent) then
begin
// the implementing instance will be edited directly
Result := TPersistent(impl);
// inject published properties from each of the extension implementers
TBaseItemDsgn(Result).InjectImplementers;
end
else
// create an instance of the designer; will automatically inject properties based on the interfaces it supports
Result := TJvDataProviderItem.Create(AnItem);
end;
function LocateReg(IID: TGUID): Integer;
begin
Result := High(GIntfPropReg);
while (Result >= 0) and not IsEqualGUID(GIntfPropReg[Result].GUID, IID) do
Dec(Result);
end;
procedure RegisterDataItemIntfProp(const IID: TGUID; const PropClass: TJvDataProviderItemClass);
var
IIDIdx: Integer;
begin
IIDIdx := LocateReg(IID);
if IIDIdx < 0 then
begin
IIDIdx := Length(GIntfPropReg);
SetLength(GIntfPropReg, IIDIdx + 1);
GIntfPropReg[IIDIdx].GUID := IID;
end;
GIntfPropReg[IIDIdx].PropClass := PropClass;
end;
function StringBaseLen(NumItems: Integer; StartString: PChar): Integer;
begin
Result := 0;
while NumItems > 0 do
begin
Inc(Result, 1 + PByte(StartString)^);
Inc(StartString, 1 + PByte(StartString)^);
Dec(NumItems);
end;
end;
function PropListSize(ListPos: PChar): Integer;
var
Cnt: Integer;
BaseInfoSize: Integer;
begin
Result := SizeOf(Word);
Cnt := PWord(ListPos)^;
Inc(ListPos, Result);
BaseInfoSize := SizeOf(TPropInfo) - SizeOf(ShortString) + 1;
while Cnt > 0 do
begin
Inc(Result, BaseInfoSize + Length(PPropInfo(ListPos)^.Name));
Inc(ListPos, BaseInfoSize + Length(PPropInfo(ListPos)^.Name));
Dec(Cnt);
end;
end;
function TypeInfoSize(TypeInfo: PTypeInfo): Integer;
var
TypeData: PTypeData;
begin
Result := 2 + Length(TypeInfo.Name);
TypeData := GetTypeData(TypeInfo);
case TypeInfo.Kind of
tkInteger, tkChar, tkEnumeration, tkSet, tkWChar:
begin
Inc(Result, SizeOf(TOrdType));
case TypeInfo.Kind of
tkInteger, tkChar, tkEnumeration, tkWChar:
begin
Inc(Result, 8);
if TypeInfo.Kind = tkEnumeration then
Inc(Result, 4 + StringBaseLen(TypeData.MaxValue - TypeData.MinValue + 1, @TypeData.NameList));
end;
tkSet:
Inc(Result, 4);
end;
end;
tkFloat:
Inc(Result, SizeOf(TFloatType));
tkString:
Inc(Result);
tkClass:
begin
Inc(Result, SizeOf(TClass) + SizeOf(PPTypeInfo) + SizeOf(Smallint) + StringBaseLen(1, @TypeData.UnitName));
Inc(Result, PropListSize(Pointer(Integer(@TypeData.UnitName) + StringBaseLen(1, @TypeData.UnitName))));
end;
end;
end;
function AllocTypeInfo(Size: Integer): PTypeInfo;
var
P: PPointer;
begin
P := AllocMem(SizeOf(P) + Size);
Inc(P);
Result := PTypeInfo(P);
end;
procedure FreeTypeInfo(ATypeInfo: PTypeInfo);
var
P: PPointer;
begin
P := PPointer(ATypeInfo);
Dec(P);
FreeMem(P);
end;
function GetOrgTypeInfo(ATypeInfo: PTypeInfo): PTypeInfo;
var
P: PPointer;
begin
P := PPointer(ATypeInfo);
Dec(P);
Result := P^;
end;
procedure SetOrgTypeInfo(ATypeInfo, Value: PTypeInfo);
var
P: PPointer;
begin
P := PPointer(ATypeInfo);
Dec(P);
P^ := Value;
end;
function CloneTypeInfo(OrgTypeInfo: PTypeInfo; AdditionalSpace: Longint = 0): PTypeInfo;
var
OrgSize: Integer;
begin
OrgSize := TypeInfoSize(OrgTypeInfo);
Result := AllocTypeInfo(OrgSize + AdditionalSpace);
SetOrgTypeInfo(Result, OrgTypeInfo);
Move(OrgTypeInfo^, Result^, OrgSize);
end;
function VMTTypeInfoFromClass(const AClass: TClass): PPTypeInfo;
var
P: {$IFDEF COMPILER12_UP}PByte{$ELSE}PChar{$ENDIF COMPILER12_UP};
begin
P := Pointer(AClass);
Inc(P, vmtTypeInfo); // Now pointing to TypeInfo of the VMT table.
Result := PPTypeInfo(P);
end;
procedure CreateTypeInfo(const AClass: TClass);
var
VMTTypeInfo: PPTypeInfo;
NewTypeInfo: PTypeInfo;
WrittenBytes: Cardinal;
begin
VMTTypeInfo := VMTTypeInfoFromClass(AClass);
{ Below the typeinfo is cloned, while an additional 2048 bytes are reserved at the end. This 2048
bytes will be used to "inject" additional properties. Since each property takes 27 + the length
of the property name bytes, assuming an average of 40 bytes/property will allow approximately 50
properties to be appended to the existing property list. }
// (rom) is there some security so we do not blow up everything by exceeding the 2048 bytes?
NewTypeInfo := CloneTypeInfo(VMTTypeInfo^, 2048);
if not WriteProtectedMemory(VMTTypeInfo, @NewTypeInfo, SizeOf(NewTypeInfo), WrittenBytes) then
FreeTypeInfo(NewTypeInfo);
end;
procedure ClearTypeInfo(const AClass: TClass);
var
VMTTypeInfo: PPTypeInfo;
OldTypeInfo, NewTypeInfo: PTypeInfo;
WrittenBytes: Cardinal;
begin
VMTTypeInfo := VMTTypeInfoFromClass(AClass);
OldTypeInfo := VMTTypeInfo^;
NewTypeInfo := GetOrgTypeInfo(OldTypeInfo);
WriteProtectedMemory(VMTTypeInfo, @NewTypeInfo, SizeOf(NewTypeInfo), WrittenBytes);
FreeTypeInfo(OldTypeInfo);
end;
function GetPropData(TypeData: PTypeData): PPropData;
begin
Result := PPropData(Integer(@TypeData.UnitName) + StringBaseLen(1, @TypeData.UnitName));
end;
procedure ClearPropList(const AClass: TClass);
var
RTTI: PTypeInfo;
TypeData: PTypeData;
PropList: PPropData;
begin
RTTI := PTypeInfo(AClass.ClassInfo);
TypeData := GetTypeData(RTTI);
TypeData.PropCount := 0;
PropList := GetPropData(TypeData);
PropList.PropCount := 0;
end;
procedure CopyPropInfo(var Source, Dest: PPropInfo; var PropNum: Smallint);
var
BaseInfoSize: Integer;
NameLen: Integer;
begin
BaseInfoSize := SizeOf(TPropInfo) - SizeOf(ShortString) + 1;
NameLen := Length(Source.Name);
Move(Source^, Dest^, BaseInfoSize + NameLen);
Dest.NameIndex := PropNum;
Inc(PChar(Source), BaseInfoSize + NameLen);
Inc(PChar(Dest), BaseInfoSize + NameLen);
Inc(PropNum);
end;
procedure AppendPropList(const AClass: TClass; PropList: PPropInfo; Count: Integer);
var
RTTI: PTypeInfo;
TypeData: PTypeData;
ClassPropList: PPropInfo;
ExistingCount: Integer;
BaseInfoSize: Integer;
PropNum: Smallint;
begin
RTTI := PTypeInfo(AClass.ClassInfo);
TypeData := GetTypeData(RTTI);
TypeData.PropCount := TypeData.PropCount + Count;
ClassPropList := PPropInfo(GetPropData(TypeData));
ExistingCount := PPropData(ClassPropList).PropCount;
PropNum := ExistingCount;
PPropData(ClassPropList).PropCount := ExistingCount + Count;
Inc(PChar(ClassPropList), 2);
BaseInfoSize := SizeOf(TPropInfo) - SizeOf(ShortString) + 1;
while ExistingCount > 0 do
begin
Inc(PChar(ClassPropList), BaseInfoSize + Length(ClassPropList.Name));
Dec(ExistingCount);
end;
while Count > 0 do
begin
CopyPropInfo(PropList, ClassPropList, PropNum);
Dec(Count);
end;
end;
{$IFNDEF COMPILER6_UP}
function GetPropList(TypeInfo: PTypeInfo; out PropList: PPropList): Integer;
begin
Result := GetTypeData(TypeInfo)^.PropCount;
if Result > 0 then
begin
GetMem(PropList, Result * SizeOf(Pointer));
TypInfo.GetPropList(TypeInfo, tkAny, PropList);
end;
end;
{$ENDIF}
//=== { TJvDataProviderItem } ================================================
constructor TJvDataProviderItem.Create(AnItem: IJvDataItem);
var
I: Integer;
IUnk: IUnknown;
PrpData: PPropData;
begin
inherited Create;
FItem := AnItem;
ClearPropList(ClassType);
for I := High(GIntfPropReg) downto 0 do
if Supports(AnItem, GIntfPropReg[I].GUID, IUnk) then
begin
PrpData := GetPropData(GetTypeData(GIntfPropReg[I].PropClass.ClassInfo));
AppendPropList(ClassType, PPropInfo(Cardinal(PrpData) + 2), PrpData.PropCount);
end;
end;
function TJvDataProviderItem.Item: IJvDataItem;
begin
Result := FItem;
end;
function TJvDataProviderItem.GetOwner: TPersistent;
begin
if Item <> nil then
Result := (Item.GetItems.Provider as IInterfaceComponentReference).GetComponent
else
Result := inherited GetOwner;
end;
function TJvDataProviderItem.GetNamePath: string;
var
Comp: TPersistent;
begin
Comp := GetOwner;
if (Comp <> nil) and (Comp is TComponent) then
Result := (Comp as TComponent).Name
else
Result := RsUnknown;
if Item <> nil then
Result := Result + ': Item[' + Item.GetID + ']'
else
Result := Result + ': ' + RsNoItem;
end;
//=== { TJvDataItemTextPropView } ============================================
type
TJvDataItemTextPropView = class(TJvDataProviderItem)
protected
function GetText: string;
procedure SetText(Value: string);
published
property Text: string read GetText write SetText;
end;
function TJvDataItemTextPropView.GetText: string;
begin
Result := (Item as IJvDataItemText).Text;
end;
procedure TJvDataItemTextPropView.SetText(Value: string);
begin
(Item as IJvDataItemText).Text := Value;
end;
//=== { TJvDataItemImagePropView } ===========================================
type
TJvDataItemImagePropView = class(TJvDataProviderItem)
protected
function GetAlignment: TAlignment;
procedure SetAlignment(Value: TAlignment);
function GetImageIndex: Integer;
procedure SetImageIndex(Value: Integer);
function GetSelectedIndex: Integer;
procedure SetSelectedIndex(Value: Integer);
published
property Alignment: TAlignment read GetAlignment write SetAlignment;
property ImageIndex: Integer read GetImageIndex write SetImageIndex;
property SelectedIndex: Integer read GetSelectedIndex write SetSelectedIndex;
end;
function TJvDataItemImagePropView.GetAlignment: TAlignment;
begin
Result := (Item as IJvDataItemImage).Alignment;
end;
procedure TJvDataItemImagePropView.SetAlignment(Value: TAlignment);
begin
(Item as IJvDataItemImage).Alignment := Value;
end;
function TJvDataItemImagePropView.GetImageIndex: Integer;
begin
Result := (Item as IJvDataItemImage).ImageIndex
end;
procedure TJvDataItemImagePropView.SetImageIndex(Value: Integer);
begin
(Item as IJvDataItemImage).ImageIndex := Value;
end;
function TJvDataItemImagePropView.GetSelectedIndex: Integer;
begin
Result := (Item as IJvDataItemImage).SelectedIndex;
end;
procedure TJvDataItemImagePropView.SetSelectedIndex(Value: Integer);
begin
(Item as IJvDataItemImage).SelectedIndex := Value;
end;
//=== { TJvDataItemsImagesPropView } =========================================
type
TJvDataItemsImagesPropView = class(TJvDataProviderItem)
protected
function GetDisabledImages: TCustomImageList;
procedure SetDisabledImages(Value: TCustomImageList);
function GetHotImages: TCustomImageList;
procedure SetHotImages(Value: TCustomImageList);
function GetImages: TCustomImageList;
procedure SetImages(Value: TCustomImageList);
published
property DisabledImages: TCustomImageList read GetDisabledImages write SetDisabledImages;
property HotImages: TCustomImageList read GetHotImages write SetHotImages;
property Images: TCustomImageList read GetImages write SetImages;
end;
function TJvDataItemsImagesPropView.GetDisabledImages: TCustomImageList;
begin
Result := (Item as IJvDataItemsImages).DisabledImages;
end;
procedure TJvDataItemsImagesPropView.SetDisabledImages(Value: TCustomImageList);
begin
(Item as IJvDataItemsImages).DisabledImages := Value;
end;
function TJvDataItemsImagesPropView.GetHotImages: TCustomImageList;
begin
Result := (Item as IJvDataItemsImages).HotImages;
end;
procedure TJvDataItemsImagesPropView.SetHotImages(Value: TCustomImageList);
begin
(Item as IJvDataItemsImages).HotImages := Value;
end;
function TJvDataItemsImagesPropView.GetImages: TCustomImageList;
begin
Result := (Item as IJvDataItemsImages).Images;
end;
procedure TJvDataItemsImagesPropView.SetImages(Value: TCustomImageList);
begin
(Item as IJvDataItemsImages).Images := Value;
end;
//=== { TBaseItemDsgn } ======================================================
{$IFDEF COMPILER10_UP}
function TBaseItemDsgn.GetDynArrayProp(Index: Integer): Pointer;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetDynArrayProp(instance, info);
end;
{$ENDIF COMPILER10_UP}
function TBaseItemDsgn.GetFloatProp(Index: Integer): Extended;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetFloatProp(instance, info);
end;
function TBaseItemDsgn.GetInt64Prop(Index: Integer): Int64;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetInt64Prop(instance, info);
end;
function TBaseItemDsgn.GetIsStoredProp(Index: Integer): Boolean;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.IsStoredProp(instance, info);
end;
{$IFDEF COMPILER6_UP}
function TBaseItemDsgn.GetInterfaceProp(Index: Integer): IInterface;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetInterfaceProp(instance, info);
end;
{$ENDIF COMPILER6_UP}
function TBaseItemDsgn.GetMethodProp(Index: Integer): TMethod;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetMethodProp(instance, info);
end;
function TBaseItemDsgn.GetOrdProp(Index: Integer): Longint;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetOrdProp(instance, info);
end;
procedure TBaseItemDsgn.GetPropDataFromIndex(Index: Integer; out Instance: TObject; out Info: PPropInfo);
var
props: PPropList;
begin
// instance is the implementer at index specified in the high-word of the Index parameter
Instance := GetImplementer(HiWord(Index));
// Retrieve the property list
GetPropList(PTypeInfo(Instance.ClassInfo), props);
try
// Get the property at the index specified in the low-word of the Index parameter
Info := props[LoWord(Index)];
finally
FreeMem(props);
end;
end;
function TBaseItemDsgn.GetStrProp(Index: Integer): string;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetStrProp(instance, info);
end;
function TBaseItemDsgn.GetVariantProp(Index: Integer): Variant;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
Result := TypInfo.GetVariantProp(instance, info);
end;
function TBaseItemDsgn.GetWideStrProp(Index: Integer): WideString;
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
{$IFDEF COMPILER6_UP}
Result := TypInfo.GetWideStrProp(instance, info);
{$ELSE ~COMPILER6_UP}
Result := TypInfo.GetStrProp(instance, info);
{$ENDIF ~COMPILER6_UP}
end;
procedure TBaseItemDsgn.InjectImplementers;
var
lstSize: Integer;
numNewProps: Integer;
implInst: TAggregatedPersistentEx;
implProps: PPropList;
destProp: PPropInfo;
destIdx: Integer;
procedure CalcAdditionalSize;
var
implIndex: Integer;
thisCount: Integer;
propIndex: Integer;
begin
lstSize := 0;
numNewProps := 0;
// iterate over the extension list
for implIndex := 0 to ImplCount - 1 do
begin
// get the implementation
implInst := GetImplementer(implIndex);
// get the property info list, including inherited properties
thisCount := GetPropList(PTypeInfo(implInst.ClassInfo), implProps);
try
// update the count
Inc(numNewProps, thisCount);
// iterate to determine size
for propIndex := 0 to thisCount - 1 do
Inc(lstSize, SizeOf(TPropInfo) - SizeOf(ShortString) + 1 + Length(implProps[propIndex].Name));
finally
FreeMem(implProps);
end;
end;
end;
function CreateClonedTypeInfo: Boolean;
var
VMTTypeInfo: PPTypeInfo;
NewTypeInfo: PTypeInfo;
WrittenBytes: Cardinal;
begin
VMTTypeInfo := VMTTypeInfoFromClass(ClassType);
// make a copy and reserve additional space to include the extension properties
NewTypeInfo := CloneTypeInfo(VMTTypeInfo^, lstSize);
// update the RTTI
Result := WriteProtectedMemory(VMTTypeInfo, @NewTypeInfo, SizeOf(NewTypeInfo), WrittenBytes);
// if this failed, free the cloned type info
if not Result then
FreeTypeInfo(NewTypeInfo);
end;
procedure InitDestinationPointer;
var
TypeData: PTypeData;
ExistingCount: Integer;
BaseInfoSize: Integer;
begin
TypeData := GetTypeData(PTypeInfo(ClassInfo));
destProp := PPropInfo(GetPropData(TypeData));
destIdx := TypeData.PropCount;
ExistingCount := PPropData(destProp).PropCount;
Inc(Integer(destProp), SizeOf(Word));
BaseInfoSize := SizeOf(TPropInfo) - SizeOf(ShortString) + 1;
while ExistingCount > 0 do
begin
Inc(Integer(destProp), BaseInfoSize + Length(destProp.Name));
Dec(ExistingCount);
end;
end;
procedure MakeNewProperty(implementationIndex, propertyIndex: Integer);
var
size: Integer;
begin;
// get the size...
size := SizeOf(TPropInfo) - SizeOf(ShortString) + 1 + Length(implProps[propertyIndex].Name);
// copy all info...
Move(implProps[propertyIndex]^, destProp^, size);
// setup name index
destProp.NameIndex := destIdx;
// advance name index
Inc(destIdx);
// setup the property index info
destProp.Index := Word(implementationIndex) shl 16 + Word(propertyIndex);
// update stored proc
destProp.StoredProc := @TBaseItemDsgn.GetIsStoredProp;
// update GetProc/SetProc
case implProps[propertyIndex].PropType^.Kind of
tkInteger, tkChar, tkEnumeration, tkSet, tkClass, tkWChar:
begin
destProp.GetProc := @TBaseItemDsgn.GetOrdProp;
destProp.SetProc := @TBaseItemDsgn.SetOrdProp;
end;
tkFloat:
begin
destProp.GetProc := @TBaseItemDsgn.GetFloatProp;
destProp.SetProc := @TBaseItemDsgn.SetFloatProp;
end;
{$IFDEF UNICODE} tkUString, {$ENDIF}
tkString, tkLString:
begin
destProp.GetProc := @TBaseItemDsgn.GetStrProp;
destProp.SetProc := @TBaseItemDsgn.SetStrProp;
end;
tkMethod:
begin
destProp.GetProc := @TBaseItemDsgn.GetMethodProp;
destProp.SetProc := @TBaseItemDsgn.SetMethodProp;
end;
tkWString:
begin
destProp.GetProc := @TBaseItemDsgn.GetWideStrProp;
destProp.SetProc := @TBaseItemDsgn.SetWideStrProp;
end;
tkVariant:
begin
destProp.GetProc := @TBaseItemDsgn.GetVariantProp;
destProp.SetProc := @TBaseItemDsgn.SetVariantProp;
end;
{$IFDEF COMPILER6_UP}
tkInterface:
begin
destProp.GetProc := @TBaseItemDsgn.GetInterfaceProp;
destProp.SetProc := @TBaseItemDsgn.SetInterfaceProp;
end;
{$ENDIF COMPILER6_UP}
tkInt64:
begin
destProp.GetProc := @TBaseItemDsgn.GetInt64Prop;
destProp.SetProc := @TBaseItemDsgn.SetInt64Prop;
end;
{$IFDEF COMPILER10_UP}
tkDynArray:
begin
destProp.GetProc := @TBaseItemDsgn.GetDynArrayProp;
destProp.SetProc := @TBaseItemDsgn.SetDynArrayProp;
end;
{$ENDIF COMPILER10_UP}
end;
// advance destination pointer
Inc(Integer(destProp), size);
end;
procedure CopyExtensionProperties;
var
implIndex: Integer;
numProps: Integer;
propIndex: Integer;
TypeData: PTypeData;
begin
// iterate over the extension list
for implIndex := 0 to ImplCount - 1 do
begin
// get the implementation
implInst := GetImplementer(implIndex);
// get the properties to add
numProps := GetPropList(PTypeInfo(implInst.ClassInfo), implProps);
try
// iterate to copy the property
for propIndex := 0 to numProps - 1 do
begin
// create a new property to reference the original one
MakeNewProperty(implIndex, propIndex);
end;
finally
FreeMem(implProps);
end;
end;
// Update the count
TypeData := GetTypeData(PTypeInfo(ClassInfo));
TypeData.PropCount := TypeData.PropCount + numNewProps;
GetPropData(TypeData).PropCount := GetPropData(TypeData).PropCount + numNewProps;
end;
begin
// Determine how much more memory we need...
CalcAdditionalSize;
// Create a clone, reserving enough additional memory for the properties of all extensions
if CreateClonedTypeInfo then
begin
// init destination pointer
InitDestinationPointer;
// Copy extension properties
CopyExtensionProperties;
end;
end;
procedure TBaseItemDsgn.RevertRTTI;
begin
ClearTypeInfo(ClassType);
end;
{$IFDEF COMPILER10_UP}
procedure TBaseItemDsgn.SetDynArrayProp(Index: Integer; Value: Pointer);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetDynArrayProp(instance, info, Value);
end;
{$ENDIF COMPILER10_UP}
procedure TBaseItemDsgn.SetFloatProp(Index: Integer; Value: Extended);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetFloatProp(instance, info, Value);
end;
procedure TBaseItemDsgn.SetInt64Prop(Index: Integer; Value: Int64);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetInt64Prop(instance, info, Value);
end;
{$IFDEF COMPILER6_UP}
procedure TBaseItemDsgn.SetInterfaceProp(Index: Integer; Value: IInterface);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetInterfaceProp(instance, info, Value);
end;
{$ENDIF COMPILER6_UP}
procedure TBaseItemDsgn.SetMethodProp(Index: Integer; Value: TMethod);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetMethodProp(instance, info, Value);
end;
procedure TBaseItemDsgn.SetOrdProp(Index, Value: Integer);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetOrdProp(instance, info, Value);
end;
procedure TBaseItemDsgn.SetStrProp(Index: Integer; Value: string);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetStrProp(instance, info, Value);
end;
procedure TBaseItemDsgn.SetVariantProp(Index: Integer; Value: Variant);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
TypInfo.SetVariantProp(instance, info, Value);
end;
procedure TBaseItemDsgn.SetWideStrProp(Index: Integer; Value: WideString);
var
instance: TObject;
info: PPropInfo;
begin
GetPropDataFromIndex(Index, instance, info);
{$IFDEF COMPILER6_UP}
TypInfo.SetWideStrProp(instance, info, Value);
{$ELSE ~COMPILER6_UP}
TypInfo.SetStrProp(instance, info, Value);
{$ENDIF ~COMPILER6_UP}
end;
//=== Registration of default interface property views =======================
procedure RegProviderItemInterfaces;
begin
RegisterDataItemIntfProp(IJvDataItemText, TJvDataItemTextPropView);
RegisterDataItemIntfProp(IJvDataItemImage, TJvDataItemImagePropView);
RegisterDataItemIntfProp(IJvDataItemsImages, TJvDataItemsImagesPropView);
end;
initialization
CreateTypeInfo(TJvDataProviderItem); // Duplicate class type info to allow properties to be injected.
RegProviderItemInterfaces; // register default interface property views.
finalization
ClearTypeInfo(TJvDataProviderItem); // undo the hacking of TJvDataProviderItem
end.