Browse Source

* TDatamodule, TResourceStream added

Michaël Van Canneyt 3 years ago
parent
commit
dfb8c2a06c
1 changed files with 389 additions and 5 deletions
  1. 389 5
      packages/rtl/classes.pas

+ 389 - 5
packages/rtl/classes.pas

@@ -17,7 +17,7 @@ unit Classes;
 interface
 
 uses
-  RTLConsts, Types, SysUtils, JS, TypInfo;
+  RTLConsts, Types, SysUtils, JS, TypInfo, p2jsres;
 
 type
   TNotifyEvent = procedure(Sender: TObject) of object;
@@ -874,6 +874,22 @@ type
     property DataString: String read GetDataString;
   end;
 
+  TFPResourceHMODULE = THandle;
+
+  { TResourceStream }
+
+  TResourceStream = class(TCustomMemoryStream)
+  private
+    procedure Initialize(aInfo : TResourceInfo);
+    procedure Initialize(Instance: TFPResourceHMODULE; Name, ResType: String);
+  public
+    constructor Create(aInfo: TResourceInfo);
+    constructor Create(Instance: TFPResourceHMODULE; const ResName, ResType : String);
+    constructor CreateFromID(Instance: TFPResourceHMODULE; ResID: Integer; ResType: String);
+    function Write(const Buffer: TBytes; Offset, Count: LongInt): LongInt; override;
+    destructor Destroy; override;
+  end;
+
 
   TFilerFlag = (ffInherited, ffChildPos, ffInline);
   TFilerFlags = set of TFilerFlag;
@@ -1407,6 +1423,52 @@ type
 
   TLoadHelperClass = Class of TLoadHelper;
 
+  { ---------------------------------------------------------------------
+      TDatamodule support
+    ---------------------------------------------------------------------}
+    TDataModule = class(TComponent)
+    private
+      FDPos: TPoint;
+      FDSize: TPoint;
+      FDPPI: Integer;
+      FOnCreate: TNotifyEvent;
+      FOnDestroy: TNotifyEvent;
+      FOldOrder : Boolean;
+      Procedure ReadP(Reader: TReader);
+      Procedure WriteP(Writer: TWriter);
+      Procedure ReadT(Reader: TReader);
+      Procedure WriteT(Writer: TWriter);
+      Procedure ReadL(Reader: TReader);
+      Procedure WriteL(Writer: TWriter);
+      Procedure ReadW(Reader: TReader);
+      Procedure WriteW(Writer: TWriter);
+      Procedure ReadH(Reader: TReader);
+      Procedure WriteH(Writer: TWriter);
+    protected
+      Procedure DoCreate; virtual;
+      Procedure DoDestroy; virtual;
+      Procedure DefineProperties(Filer: TFiler); override;
+      Procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
+      Function HandleCreateException: Boolean; virtual;
+      Procedure ReadState(Reader: TReader); override;
+    public
+      constructor Create(AOwner: TComponent); override;
+      Constructor CreateNew(AOwner: TComponent);
+      Constructor CreateNew(AOwner: TComponent; CreateMode: Integer); virtual;
+      destructor Destroy; override;
+      Procedure AfterConstruction; override;
+      Procedure BeforeDestruction; override;
+      property DesignOffset: TPoint read FDPos write FDPos;
+      property DesignSize: TPoint read FDSize write FDSize;
+      property DesignPPI: Integer read FDPPI write FDPPI;
+    published
+      property OnCreate: TNotifyEvent read FOnCreate write FOnCreate;
+      property OnDestroy: TNotifyEvent read FOnDestroy write FOnDestroy;
+      property OldCreateOrder: Boolean read FOldOrder write FOldOrder;
+    end;
+    TDataModuleClass = Class of TDataModule;
+
+
 type
   TIdentMapEntry = record
     Value: Integer;
@@ -1426,6 +1488,8 @@ procedure RegisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalCompo
 procedure UnregisterFindGlobalComponentProc(AFindGlobalComponent: TFindGlobalComponent);
 function FindGlobalComponent(const Name: string): TComponent;
 Function FindNestedComponent(Root : TComponent; APath : String; CStyle : Boolean = True) : TComponent;
+function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
+
 procedure RedirectFixupReferences(Root: TComponent; const OldRootName, NewRootName: string);
 procedure RemoveFixupReferences(Root: TComponent; const RootName: string);
 procedure RegisterIntegerConsts(IntegerType: Pointer; IdentToIntFn: TIdentToInt;  IntToIdentFn: TIntToIdent);
@@ -1452,6 +1516,18 @@ procedure BeginGlobalLoading;
 procedure NotifyGlobalLoading;
 procedure EndGlobalLoading;
 
+Type
+  TDataModuleNotifyEvent = procedure (DataModule: TDataModule) of object;
+  TExceptionNotifyEvent = procedure (E: Exception) of object;
+
+var
+  // IDE hooks for TDatamodule support.
+  AddDataModule              : TDataModuleNotifyEvent;
+  RemoveDataModule           : TDataModuleNotifyEvent;
+  ApplicationHandleException : TNotifyEvent;
+  ApplicationShowException   : TExceptionNotifyEvent;
+  FormResourceIsText : Boolean = True;
+
 Const
   // Some aliases
   vaSingle = vaDouble;
@@ -1543,6 +1619,66 @@ type
       AIntToIdent: TIntToIdent);
   end;
 
+{ TResourceStream }
+
+// We need a polyfill for nodejs.
+Function atob (s : String) : string; external name 'atob';
+
+procedure TResourceStream.Initialize(aInfo: TResourceInfo);
+
+var
+  Ptr : TJSArrayBuffer;
+  S : String;
+
+begin
+  if aInfo.encoding<>'base64' then
+    Raise ENotSupportedException.CreateFmt(SErrResourceNotBase64,[aInfo.name]);
+  S:=atob(aInfo.Data);
+  Ptr:=StringToBuffer(S, length(S));
+  SetPointer(Ptr,Ptr.byteLength);
+end;
+
+procedure TResourceStream.Initialize(Instance: TFPResourceHMODULE; Name, ResType: String);
+
+Var
+  aInfo : TResourceInfo;
+
+begin
+  if not GetResourceInfo(Name, aInfo) then
+    raise EResNotFound.CreateFmt(SResNotFound,[Name]);
+  Initialize(aInfo);
+end;
+
+constructor TResourceStream.Create(aInfo: TResourceInfo);
+begin
+  inherited create;
+  Initialize(aInfo);
+end;
+
+constructor TResourceStream.Create(Instance: TFPResourceHMODULE; const ResName, ResType: String);
+begin
+  inherited create;
+  Initialize(Instance,ResName,ResType);
+end;
+
+constructor TResourceStream.CreateFromID(Instance: TFPResourceHMODULE;
+  ResID: Integer; ResType: String);
+begin
+  inherited create;
+  Initialize(Instance,IntToStr(ResID),ResType);
+end;
+
+function TResourceStream.Write(const Buffer: TBytes; Offset, Count: LongInt
+  ): LongInt;
+begin
+  Raise ENotSupportedException.Create(SErrResourceStreamNoWrite);
+end;
+
+destructor TResourceStream.Destroy;
+begin
+  inherited Destroy;
+end;
+
 { TStringStream }
 
 function TStringStream.GetDataString: String;
@@ -9626,6 +9762,11 @@ end;
 { ---------------------------------------------------------------------
   Global routines
   ---------------------------------------------------------------------}
+Type
+  TInitHandler = Class(TObject)
+    AHandler : TInitComponentHandler;
+    AClass : TComponentClass;
+  end;
 
 var
   ClassList : TJSObject;
@@ -9735,11 +9876,29 @@ begin
     end;
 end;
 
-Type
-  TInitHandler = Class(TObject)
-    AHandler : TInitComponentHandler;
-    AClass : TComponentClass;
+function InitInheritedComponent(Instance: TComponent; RootAncestor: TClass): Boolean;
+Var
+  I : Integer;
+begin
+  I:=0;
+  if not Assigned(InitHandlerList) then begin
+    Result := True;
+    Exit;
   end;
+  Result:=False;
+  With InitHandlerList do
+    begin
+    I:=0;
+    // Instance is the normally the lowest one, so that one should be used when searching.
+    While Not result and (I<Count) do
+      begin
+      If (Instance.InheritsFrom(TInitHandler(Items[i]).AClass)) then
+        Result:=TInitHandler(Items[i]).AHandler(Instance,RootAncestor);
+      Inc(I);
+      end;
+    end;
+end;
+
 
 
 procedure RegisterInitComponentHandler(ComponentClass: TComponentClass;   Handler: TInitComponentHandler);
@@ -10933,7 +11092,232 @@ begin
 end;
 
 
+{ ----------------------------------------------------------------------
+  TDatamodule
+  ----------------------------------------------------------------------}
+
+Constructor TDataModule.Create(AOwner: TComponent);
+begin
+  CreateNew(AOwner);
+  if (ClassType <> TDataModule) and
+     not (csDesigning in ComponentState) then
+    begin
+    if not InitInheritedComponent(Self, TDataModule) then
+      raise EStreamError.CreateFmt(SErrNoSTreaming, [ClassName]);
+    if OldCreateOrder then
+      DoCreate;
+    end;
+end;
+
+Constructor TDataModule.CreateNew(AOwner: TComponent);
+
+begin
+  CreateNew(AOwner,0);
+end;
+
+constructor TDataModule.CreateNew(AOwner: TComponent; CreateMode: Integer);
+begin
+  inherited Create(AOwner);
+  FDPPI := 96;
+  if Assigned(AddDataModule) and (CreateMode>=0) then
+    AddDataModule(Self);
+end;
+
+Procedure TDataModule.AfterConstruction;
+begin
+   If not OldCreateOrder then
+     DoCreate;
+end;
+
+Procedure TDataModule.BeforeDestruction;
+begin
+  Destroying;
+  RemoveFixupReferences(Self, '');
+  if not OldCreateOrder then
+    DoDestroy;
+end;
+
+destructor TDataModule.Destroy;
+begin
+  if OldCreateOrder then
+    DoDestroy;
+  if Assigned(RemoveDataModule) then
+    RemoveDataModule(Self);
+  inherited Destroy;
+end;
+
+Procedure TDataModule.DoCreate;
+begin
+  if Assigned(FOnCreate) then
+    try
+      FOnCreate(Self);
+    except
+      if not HandleCreateException then
+        raise;
+    end;
+end;
+
+Procedure TDataModule.DoDestroy;
+begin
+  if Assigned(FOnDestroy) then
+    try
+      FOnDestroy(Self);
+    except
+      if Assigned(ApplicationHandleException) then
+        ApplicationHandleException(Self);
+    end;
+end;
+
+procedure TDataModule.DefineProperties(Filer: TFiler);
+
+var
+  Ancestor : TDataModule;
+  HaveData,
+  HavePPIData: Boolean;
+
+begin
+  inherited DefineProperties(Filer);
+  Ancestor := TDataModule(Filer.Ancestor);
+  HaveData:=(Ancestor=Nil) or
+            (FDSize.X<>Ancestor.FDSize.X) or
+            (FDSize.Y<>Ancestor.FDSize.Y) or
+            (FDPos.Y<>Ancestor.FDPos.Y) or
+            (FDPos.X<>Ancestor.FDPos.X);
+  HavePPIData:=(Assigned(Ancestor) and (FDPPI<>Ancestor.FDPPI)) or
+               (not Assigned(Ancestor) and (FDPPI<>96));
+  Filer.DefineProperty('Height', @ReadH, @WriteH, HaveData);
+  Filer.DefineProperty('HorizontalOffset', @ReadL, @WriteL, HaveData);
+  Filer.DefineProperty('VerticalOffset', @ReadT,@WriteT, HaveData);
+  Filer.DefineProperty('Width', @ReadW, @WriteW, HaveData);
+  Filer.DefineProperty('PPI', @ReadP, @WriteP,HavePPIData);
+end;
+
+procedure TDataModule.GetChildren(Proc: TGetChildProc; Root: TComponent);
+
+var
+  I : Integer;
+
+begin
+  inherited GetChildren(Proc, Root);
+  if (Root=Self) then
+    for I:=0 to ComponentCount-1 do
+      If Not Components[I].HasParent then
+         Proc(Components[i]);
+end;
+
+
+function TDataModule.HandleCreateException: Boolean;
+begin
+  Result:=Assigned(ApplicationHandleException);
+  if Result then
+    ApplicationHandleException(Self);
+end;
+
+Procedure TDataModule.ReadP(Reader: TReader);
+begin
+  FDPPI := Reader.ReadInteger;
+end;
+
+Procedure TDataModule.ReadState(Reader: TReader);
+begin
+  FOldOrder := false;
+  inherited ReadState(Reader);
+end;
+
+Procedure TDataModule.ReadT(Reader: TReader);
+begin
+  FDPos.Y := Reader.ReadInteger;
+end;
+
+Procedure TDataModule.WriteT(Writer: TWriter);
+begin
+  Writer.WriteInteger(FDPos.Y);
+end;
+
+Procedure TDataModule.ReadL(Reader: TReader);
+begin
+  FDPos.X := Reader.ReadInteger;
+end;
+
+Procedure TDataModule.WriteL(Writer: TWriter);
+begin
+  Writer.WriteInteger(FDPos.X);
+end;
+
+Procedure TDataModule.ReadW(Reader: TReader);
+begin
+  FDSIze.X := Reader.ReadInteger;
+end;
+
+Procedure TDataModule.WriteP(Writer: TWriter);
+begin
+  Writer.WriteInteger(FDPPI);
+end;
+
+Procedure TDataModule.WriteW(Writer: TWriter);
+begin
+  Writer.WriteInteger(FDSIze.X);
+end;
+
+Procedure TDataModule.ReadH(Reader: TReader);
+begin
+  FDSIze.Y := Reader.ReadInteger;
+end;
+
+Procedure TDataModule.WriteH(Writer: TWriter);
+begin
+  Writer.WriteInteger(FDSIze.Y);
+end;
+
+function CreateComponentfromRes(const res : string;Inst : THandle; var Component : TComponent) : Boolean;
+
+var
+  ResStream : TResourceStream;
+
+  Src : TStream;
+  aInfo : TResourceInfo;
+
+begin
+  result:=GetResourceInfo(Res,aInfo);
+  if Result then
+    begin
+    ResStream:=TResourceStream.Create(aInfo);
+    try
+      if Not FormResourceIsText then
+        Src:=ResStream
+      else
+        begin
+        Src:=TMemoryStream.Create;
+        ObjectTextToBinary(ResStream,Src);
+        Src.Position:=0;
+        end;
+      Component:=Src.ReadComponent(Component);
+    finally
+      if Src<>ResStream then
+        Src.Free;
+      ResStream.Free;
+    end;
+    end;
+end;
+
+function DefaultInitHandler(Instance: TComponent; RootAncestor: TClass): Boolean;
+
+  function doinit(_class : TClass) : boolean;
+    begin
+      result:=false;
+      if (_class.ClassType=TComponent) or (_class.ClassType=RootAncestor) then
+        exit;
+      result:=doinit(_class.ClassParent);
+      // Resources are written with their unit name
+      result:=CreateComponentfromRes(_class.UnitName,0,Instance) or result;
+    end;
+
+begin
+  result:=doinit(Instance.ClassType);
+end;
+
 initialization
+  RegisterInitComponentHandler(TDataModule,@DefaultInitHandler);
   ClassList:=TJSObject.New;
 end.