home *** CD-ROM | disk | FTP | other *** search
/ Chip 2002 September / Chip_2002-09_cd1.bin / zkuste / delphi / kolekce / d56 / XMLCOMP.ZIP / DnXmlPropMapper.pas < prev    next >
Pascal/Delphi Source File  |  2002-06-14  |  10KB  |  322 lines

  1. unit DnXmlPropMapper;
  2.  
  3. interface
  4.  
  5. uses
  6.   Classes, SysUtils, TypInfo;
  7.  
  8. type
  9.   {:Baseclass to derive your custom property mapper from. Object properties must be sorted so the
  10.     readonly properties come first.}  
  11.   TDnXmlPropMapper = class
  12.   private
  13.     FObject: TObject;
  14.     FStoreReadOnlyProps: Boolean;
  15.   protected
  16.     function GetCount: Integer; virtual; abstract;
  17.     function GetIsStored(aIndex: Integer): Boolean; virtual; abstract;
  18.     function GetValue(aIndex: Integer): string; virtual; abstract;
  19.     procedure SetValue(aIndex: Integer; const Value: string); virtual; abstract;
  20.     function GetPropName(aIndex: Integer): string; virtual; abstract;
  21.     function GetIsObject(aIndex: Integer): Boolean; virtual; abstract;
  22.     function GetIsAssignableObject(aIndex: Integer): Boolean; virtual; abstract;
  23.     function GetIsRef(aIndex: Integer): Boolean; virtual; abstract;
  24.     function GetObjectProp(aIndex: Integer): TObject; virtual; abstract;
  25.     procedure SetObjectProp(aIndex: Integer; const Value: TObject); virtual; abstract;
  26.     property TheObject: TObject read FObject;
  27.   public
  28.     {:Always use this constructor instead of the standard one! It takes the
  29.       object of which the properties are needed.}
  30.     constructor CreateWithObject(aObject: TObject); overload; virtual; 
  31.     property Count: Integer read GetCount;
  32.     property IsStored[aIndex: Integer]: Boolean read GetIsStored;
  33.     property Value[aIndex: Integer]: string read GetValue write SetValue;
  34.     property PropName[aIndex: Integer]: string read GetPropName;
  35.     property StoreReadOnlyProps: Boolean read FStoreReadOnlyProps write FStoreReadOnlyProps;
  36.     // object specific
  37.     property ObjectProp[aIndex: Integer]: TObject read GetObjectProp write SetObjectProp;
  38.     property IsObject[aIndex: Integer]: Boolean read GetIsObject;
  39.     property IsAssignableObject[aIndex: Integer]: Boolean read GetIsAssignableObject;
  40.     property IsRef[aIndex: Integer]: Boolean read GetIsRef;
  41.   end;
  42.  
  43.   TDnXmlRttiPropMapper = class(TDnXmlPropMapper)
  44.   private
  45.     FProps: TList;
  46.     FPropKinds: TTypeKinds;
  47.     function Props(aIndex: Integer): PPropInfo;
  48.     procedure UpdateProps;
  49.     procedure SetPropKinds(const Value: TTypeKinds);
  50.   protected
  51.     function GetCount: Integer; override;
  52.     function GetIsStored(aIndex: Integer): Boolean; override;
  53.     function GetValue(aIndex: Integer): string; override;
  54.     procedure SetValue(aIndex: Integer; const Value: string); override;
  55.     function GetPropName(aIndex: Integer): string; override;
  56.     // object specific
  57.     function GetIsObject(aIndex: Integer): Boolean; override;
  58.     function GetIsAssignableObject(aIndex: Integer): Boolean; override;
  59.     function GetIsRef(aIndex: Integer): Boolean; override;
  60.     function GetObjectProp(aIndex: Integer): TObject; override;
  61.     procedure SetObjectProp(aIndex: Integer; const Value: TObject); override;
  62.   public
  63.     constructor CreateWithObject(aObject: TObject); override;
  64.     destructor Destroy; override;
  65.     {:Which kind of properties to map. Kind not in the list will not be mapped.}
  66.     property PropKinds: TTypeKinds read FPropKinds write SetPropKinds default tkProperties;
  67.   end;
  68.  
  69.   TDnXmlPropMapperClass = class of TDnXmlPropMapper;
  70.  
  71. {:Returns the property mapper associated with a certain class. 0 <= aIndex < GetXmlPropMapperCount().}
  72. function GetXmlPropMapper(aClass: TClass; aIndex: Integer): TDnXmlPropMapperClass;
  73. {:Returns the number of property mappers associated with a certain class.}
  74. function GetXmlPropMapperCount(aClass: TClass): Integer;
  75. {:Registers (associates) a property mapper to a certain component class. The class must be derived from
  76.   TComponent.}
  77. procedure RegisterPropMapper(aClass: TComponentClass; aMapper: TDnXmlPropMapperClass);
  78. {:Unregisters the propmapper (registered using the RegisterPropMapper routine) for a specific class.}
  79. procedure UnregisterPropMapperForClass(aClass: TComponentClass; aMapper: TDnXmlPropMapperClass);
  80. {:Unregisters the propmapper (registered using the RegisterPropMapper routine)  for all classes it was associated with.}
  81. procedure UnregisterPropMapper(aMapper: TDnXmlPropMapperClass);
  82.  
  83. implementation
  84.  
  85. uses
  86.   Contnrs;
  87.  
  88. var
  89.   uClasses: TList = nil; { of TClass }
  90.   uMappers: TObjectList = nil; { of TList of TDnXmlPropMapperClass }
  91.  
  92. function GetXmlPropMapper(aClass: TClass; aIndex: Integer): TDnXmlPropMapperClass;
  93. var idx: Integer;
  94. begin
  95.   result := nil;
  96.   for idx := 0 to uClasses.Count - 1 do
  97.   begin
  98.     if aClass.InheritsFrom(uClasses[idx]) then
  99.     begin
  100.       if aIndex < TList(uMappers[idx]).Count then
  101.         result := TList(uMappers[idx])[aIndex]
  102.       else
  103.         Dec(aIndex, TList(uMappers[idx]).Count);
  104.     end;
  105.   end;
  106. end;
  107.  
  108. function GetXmlPropMapperCount(aClass: TClass): Integer;
  109. var idx: Integer;
  110. begin
  111.   result := 0;
  112.   for idx := 0 to uClasses.Count - 1 do
  113.   begin
  114.     if aClass.InheritsFrom(uClasses[idx]) then
  115.     begin
  116.       result := result + TList(uMappers[idx]).Count;
  117.     end;
  118.   end;
  119. end;
  120.  
  121. procedure RegisterPropMapper(aClass: TComponentClass; aMapper: TDnXmlPropMapperClass);
  122. var idx: Integer;
  123.     mappers: TList;
  124. begin
  125.   Assert(aClass <> nil);
  126.   Assert(aMapper <> nil);
  127.  
  128.   idx := uClasses.IndexOf(aClass);
  129.   if idx <> -1 then
  130.     mappers := TList(uMappers[idx])
  131.   else
  132.   begin
  133.     mappers := TList.Create;
  134.     uMappers.Add(mappers);
  135.     uClasses.Add(aClass);
  136.   end;
  137.  
  138.   mappers.Add(aMapper);
  139. end;
  140.  
  141. procedure UnregisterPropMapperForClass(aClass: TComponentClass; aMapper: TDnXmlPropMapperClass);
  142. var idx: Integer;
  143.     mappers: TList;
  144. begin
  145.   Assert(aClass <> nil);
  146.  
  147.   if aClass <> nil then
  148.   begin
  149.     idx := uClasses.IndexOf(aClass);
  150.     if idx = -1 then
  151.       raise Exception.CreateFmt('There was no mapper registered for class %s', [aClass.ClassName]);
  152.     mappers := TList(uMappers[idx]);
  153.     mappers.Remove(aMapper);
  154.     if mappers.Count = 0 then
  155.     begin
  156.       uClasses.Delete(idx);
  157.       uMappers.Delete(idx);
  158.     end
  159.   end;
  160. end;
  161.  
  162. procedure UnregisterPropMapper(aMapper: TDnXmlPropMapperClass);
  163. var idx: Integer;
  164.     mappers: TList;
  165. begin
  166.   Assert(aMapper <> nil);
  167.  
  168.   idx := 0;
  169.   while idx < uMappers.Count - 1 do
  170.   begin
  171.     mappers := TList(uMappers[idx]);
  172.     mappers.Remove(aMapper);
  173.     if mappers.Count = 0 then
  174.     begin
  175.       uMappers.Delete(idx);
  176.       uClasses.Delete(idx);
  177.     end
  178.     else
  179.       inc(idx);
  180.   end;
  181. end;
  182.  
  183. { TDnXmlPropMapper }
  184.  
  185. constructor TDnXmlPropMapper.CreateWithObject(aObject: TObject);
  186. begin
  187.   inherited Create;
  188.   Assert(aObject <> nil);
  189.   FObject := aObject;
  190. end;
  191.  
  192. { TDnXmlRttiPropMapper }
  193.  
  194. constructor TDnXmlRttiPropMapper.CreateWithObject(aObject: TObject);
  195. begin
  196.   inherited;
  197.   FPropKinds := tkProperties;
  198.   UpdateProps;
  199. end;
  200.  
  201. destructor TDnXmlRttiPropMapper.Destroy;
  202. begin
  203.   FProps.Free;
  204.   inherited;
  205. end;
  206.  
  207. function TDnXmlRttiPropMapper.GetCount: Integer;
  208. begin
  209.   result := FProps.Count;
  210. end;
  211.  
  212. function TDnXmlRttiPropMapper.GetIsObject(aIndex: Integer): Boolean;
  213. begin
  214.   result := Props(aIndex).PropType^.Kind = tkClass;
  215. end;
  216.  
  217. function TDnXmlRttiPropMapper.GetIsStored(aIndex: Integer): Boolean;
  218. begin
  219.   result := IsStoredProp(TheObject, FProps[aIndex]);
  220.   if result then
  221.   begin
  222.     if not StoreReadOnlyProps then
  223.     begin
  224.       if not IsObject[aIndex] then
  225.         result := Assigned(Props(aIndex).SetProc);
  226.     end;
  227.   end;
  228. end;
  229.  
  230. function TDnXmlRttiPropMapper.GetPropName(aIndex: Integer): string;
  231. begin
  232.   result := Props(aIndex).Name;
  233. end;
  234.  
  235. function TDnXmlRttiPropMapper.GetValue(aIndex: Integer): string;
  236. begin
  237.   Assert(not IsObject[aIndex]);
  238.   result := GetPropValue(TheObject, PropName[aIndex]);
  239. end;
  240.  
  241. procedure TDnXmlRttiPropMapper.SetValue(aIndex: Integer; const Value: string);
  242. begin
  243.   Assert(not IsObject[aIndex]);
  244.   SetPropValue(TheObject, PropName[aIndex], Value);
  245. end;
  246.  
  247. function TDnXmlRttiPropMapper.GetObjectProp(aIndex: Integer): TObject;
  248. begin
  249.   Assert(IsObject[aIndex]);
  250.   result := TObject(GetOrdProp(TheObject, FProps[aIndex]));
  251. end;
  252.  
  253. procedure TDnXmlRttiPropMapper.SetObjectProp(aIndex: Integer; const Value: TObject);
  254. begin
  255.   Assert(IsAssignableObject[aIndex]);
  256.   SetOrdProp(TheObject, FProps[aIndex], Integer(Value));
  257. end;
  258.  
  259. function TDnXmlRttiPropMapper.GetIsRef(aIndex: Integer): Boolean;
  260. begin
  261.   Assert(IsObject[aIndex]);
  262.  
  263.   if GetObjectProp(aIndex) is TComponent then
  264.     result := TComponent(ObjectProp[aIndex]).Owner <> TheObject
  265.   else
  266.     result := False;
  267. end;
  268.  
  269. function TDnXmlRttiPropMapper.GetIsAssignableObject(
  270.   aIndex: Integer): Boolean;
  271. begin
  272.   Assert(IsObject[aIndex]);
  273.   result := Assigned(Props(aIndex).SetProc);
  274. end;
  275.  
  276. function TDnXmlRttiPropMapper.Props(aIndex: Integer): PPropInfo;
  277. begin
  278.   result := PPropInfo(FProps[aIndex]);
  279. end;
  280.  
  281. procedure TDnXmlRttiPropMapper.UpdateProps;
  282. var temp: PPropList;
  283.     count,i: Integer;
  284. begin
  285.   count := GetTypeData(FObject.ClassInfo).PropCount;
  286.   GetMem(temp, count * SizeOf(PPropInfo));
  287.   try
  288.     GetPropInfos(FObject.ClassInfo, temp);
  289.  
  290.     FProps := TList.Create;
  291.     // filter props
  292.     for i := 0 to count - 1 do
  293.     begin
  294.       if temp[i].PropType^.Kind in PropKinds then
  295.         FProps.Add(temp[i]);
  296.     end;
  297.   finally
  298.     FreeMem(temp);
  299.   end;
  300. end;
  301.  
  302. procedure TDnXmlRttiPropMapper.SetPropKinds(const Value: TTypeKinds);
  303. begin
  304.   if FPropKinds <> Value then
  305.   begin
  306.     FPropKinds := Value;
  307.     UpdateProps;
  308.   end;
  309. end;
  310.  
  311. initialization
  312.   uClasses := TList.Create;
  313.   uMappers := TObjectList.Create;
  314.   RegisterPropMapper(TComponent, TDnXmlRttiPropMapper);
  315.  
  316. finalization
  317.   uClasses.Free;
  318.   uMappers.Free;
  319.   UnRegisterPropMapper(TDnXmlRttiPropMapper);
  320.  
  321. end.
  322.