unit uClassRegistryUtils; interface uses Classes, SysUtils, Forms, uGUIBase; type IClassRegistry = Interface ['{FD23C946-4103-4C67-9C3F-644B52826833}'] procedure RegisterClass( aClass: TClass; const aDisplayname: String = ''); procedure RegisterClasses( const aClasses: array of TClass; const aDisplaynames: array of String ); procedure UnRegisterClass( aClass: TClass ); function FindClass( const aClassOrDisplayname: String ): Tclass; function IsClassRegistered( aClass: TClass ): Boolean; overload; function IsClassRegistered( const aDisplayname: String ): Boolean; overload; procedure GetRegisteredClasses( aList: TStrings; aMinClass: TClass = nil); function CreateObject( const aClassOrDisplayname: String ): TObject; end; IComponentRegistry = Interface( IClassRegistry ) ['{04BAA01F-9AF4-4E60-9922-641E127A35C2}'] function CreateComponent( const aClassOrDisplayname: String; aOwner:TComponent = nil ): TComponent; end; IFormRegistry = Interface( IComponentRegistry ) ['{28E3BF72-1378-4136-B1FB-027FBB8FE99B}'] function CreateForm( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TForm; end; IDataModuleRegistry = Interface( IComponentRegistry ) ['{9D8D1D23-6A5C-4351-9393-093CD8B76788}'] function CreateDatamodule( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TDatamodule; end; IReportRegistry = Interface( IComponentRegistry ) ['{49D3C8D5-8FEE-4F15-A6D2-51CB1DB29F8D}'] function CreateReport( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TInterfacedObject; end; TClassRegistry = class( TInterfacedObject, IClassRegistry ) private FList: TStringlist; FMinAcceptableClass: TClass; function FindClassByClassname( const aClassname: String ): Tclass; function FindClassByDisplayname( const aDisplayname: String ): TClass; function IsClassAcceptable( aClass: TClass ): Boolean; function GetClasses(index: integer): TClass; function GetCount: Integer; protected procedure ValidateMinAcceptableClass(var aMinAcceptableClass: TClass ); virtual; procedure RegisterClass( aClass: TClass; const aDisplayname: String = ''); procedure RegisterClasses( const aClasses: array of TClass; const aDisplaynames: array of String ); procedure UnRegisterClass( aClass: TClass ); function FindClass( const aClassOrDisplayname: String ): Tclass; function IsClassRegistered( aClass: TClass ): Boolean; overload; function IsClassRegistered( const aDisplayname: String ): Boolean; overload; procedure GetRegisteredClasses( aList: TStrings; aMinClass: TClass = nil); function CreateObject( const aClassOrDisplayname: String ): TObject; property MinAcceptableClass: TClass read FMinAcceptableClass; property List: TStringlist read FList; property Count: Integer read GetCount; property Classes[ index: integer ]: TClass read GetClasses; public constructor Create( minAcceptableClass: TClass = nil ); virtual; destructor Destroy; override; end; TComponentRegistry = class( TClassRegistry, IComponentRegistry ) protected procedure ValidateMinAcceptableClass(var aMinAcceptableClass: TClass ); override; function CreateComponent( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TComponent; end; TFormRegistry = class( TComponentRegistry, IFormRegistry ) protected procedure ValidateMinAcceptableClass(var aMinAcceptableClass: TClass ); override; function CreateForm( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TForm; end; TDataModuleRegistry = class( TComponentRegistry, IDataModuleRegistry ) protected procedure ValidateMinAcceptableClass(var aMinAcceptableClass: TClass); override; function CreateDatamodule( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TDatamodule; end; TReportRegistry = class( TComponentRegistry, IReportRegistry ) protected procedure ValidateMinAcceptableClass(var aMinAcceptableClass: TClass ); override; function CreateReport( const aClassOrDisplayname: String; aOwner: TComponent = nil ): TInterfacedObject; end; EClassRegistryError = class( Exception ); implementation { TClassRegistry } ResourceString eClassnotFound = 'Class "%s" was not found in the registry.'; constructor TClassRegistry.Create(minAcceptableClass: TClass); begin inherited Create; FList := Tstringlist.Create; ValidateMinAcceptableClass( minAcceptableClass ); FMinAcceptableClass := minAcceptableClass; end; function TClassRegistry.CreateObject( const aClassOrDisplayname: String): TObject; begin Result := FindClass( aClassOrDisplayname ).Create; end; destructor TClassRegistry.Destroy; begin Flist.Free; inherited; end; function TClassRegistry.FindClass( const aClassOrDisplayname: String): Tclass; begin Result := FindClassByDisplayname( aClassOrDisplayname ); If not Assigned( Result ) Then Result := FindClassByClassname( aClassOrDisplayname ); If not Assigned( Result ) Then raise EClassRegistryError.CreateFmt ( eClassnotFound, [ aClassOrDisplayname ] ); end; function TClassRegistry.FindClassByClassname( const aClassname: String): Tclass; var i: Integer; begin for i:= 0 to count-1 do begin Result := classes[i]; If Result.ClassNameIs( aClassname ) Then Exit; end; Result := nil; end; function TClassRegistry.FindClassByDisplayname( const aDisplayname: String): TClass; var i: Integer; begin i:= List.IndexOf( aDisplayname ); If i >= 0 Then Result := Classes[i] Else Result := nil; end; function TClassRegistry.GetClasses(index: integer): TClass; begin Result := TClass( List.Objects[index] ); end; function TClassRegistry.GetCount: Integer; begin Result := List.Count; end; procedure TClassRegistry.GetRegisteredClasses(aList: TStrings; aMinClass: TClass); var i: Integer; aClass: TClass; begin Assert( Assigned( aList )); aList.BeginUpdate; try aList.Clear; If not Assigned( aMinClass ) Then aList.Assign( List ) else begin For i:= 0 To Count-1 Do Begin aClass := Classes[i]; If aClass.InheritsFrom( aMinClass ) Then aList.AddObject( List[i], TObject( aClass )); end; end; finally aList.EndUpdate end; end; function TClassRegistry.IsClassAcceptable(aClass: TClass): Boolean; begin Result := Assigned( aClass ) and aClass.InheritsFrom( MinAcceptableClass ); end; function TClassRegistry.IsClassRegistered(const aDisplayname: String): Boolean; begin Result := List.IndexOf(aDisplayname) >= 0; end; function TClassRegistry.IsClassRegistered(aClass: TClass): Boolean; begin Result := List.IndexOfObject( TObject( aClass )) >= 0; end; procedure TClassRegistry.RegisterClass(aClass: TClass; const aDisplayname: String); begin Assert( Assigned( aClass ), 'Cannot register Nil class' ); If aDisplayname = '' Then RegisterClass( aClass, aClass.Classname ) else begin Assert( IsClassAcceptable( aClass ), format('Cannot register %s since it does not inherit from %s', [aclass.classname, MinAcceptableClass.classname] )); Assert( not IsClassRegistered( aClass ), Format('Class %s is already registered.', [aClass.Classname])); List.AddObject( aDisplayname, TObject( aClass )); end; end; procedure TClassRegistry.RegisterClasses(const aClasses: array of TClass; const aDisplaynames: array of String); var i: Integer; begin Assert( High( aClasses ) = High( aDisplaynames ), 'Size of both parameter arrays has to be the same.' ); for i:= Low( aClasses ) to High( aClasses ) do RegisterClass( aClasses[i], aDisplaynames[i] ); end; procedure TClassRegistry.UnRegisterClass(aClass: TClass); var i: Integer; begin i:= List.IndexOfObject( TObject( aClass )); If i >= 0 Then List.Delete( i ); // does not consider attempt to unregister a class that is not // registered as an error. end; procedure TClassRegistry.ValidateMinAcceptableClass( var aMinAcceptableClass: TClass); begin If not Assigned( aMinAcceptableClass ) Then aMinAcceptableClass := TObject; end; { TComponentRegistry } function TComponentRegistry.CreateComponent( const aClassOrDisplayname: String; aOwner: TComponent): TComponent; var aClass: TComponentClass; begin aClass := TComponentClass( FindClass( aClassOrDisplayname )); Result := aClass.Create( aOwner ); end; procedure TComponentRegistry.ValidateMinAcceptableClass( var aMinAcceptableClass: TClass); begin inherited; If not aMinAcceptableClass.InheritsFrom( TComponent ) Then aMinAcceptableClass := TComponent; end; { TFormRegistry } function TFormRegistry.CreateForm(const aClassOrDisplayname: String; aOwner: TComponent): TForm; begin Result := CreateComponent( aClassOrDisplayname, aOwner ) As TForm; end; procedure TFormRegistry.ValidateMinAcceptableClass( var aMinAcceptableClass: TClass); begin inherited; If not aMinAcceptableClass.InheritsFrom( TForm ) Then aMinAcceptableClass := TForm; end; { TDataModuleRegistry } function TDataModuleRegistry.CreateDatamodule( const aClassOrDisplayname: String; aOwner: TComponent): TDatamodule; begin Result := CreateComponent( aClassOrDisplayname, aOwner ) As TDatamodule; end; procedure TDataModuleRegistry.ValidateMinAcceptableClass( var aMinAcceptableClass: TClass); begin inherited; If not aMinAcceptableClass.InheritsFrom( TDatamodule ) Then aMinAcceptableClass := TDatamodule; end; { TReportRegistry } function TReportRegistry.CreateReport(const aClassOrDisplayname: String; aOwner: TComponent): TInterfacedObject; begin Result := CreateObject( aClassOrDisplayname) As TInterfacedObject; // Result := CreateComponent( aClassOrDisplayname, aOwner ) As TInterfacedObject; end; procedure TReportRegistry.ValidateMinAcceptableClass( var aMinAcceptableClass: TClass); begin inherited; If not aMinAcceptableClass.InheritsFrom( TInterfacedObject ) Then aMinAcceptableClass := TInterfacedObject; end; end.