unit FormUtl;{v0.60}
interface
uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls,
  TypInfo, WinUtl, PropUtl{v0.61}, RTTIUnit{/v0.61};

{ Copy values of published properties of AObject to those input controls
  of AForm that has Name property that starts with the name of some
  AObject's property (case sensitive) and continues with "_" or nothing.
  Sets AForm.Tag to $FFFF during the procedure run. }
procedure ObjectToForm(AObject: TObject; AForm: TForm);

{ Does the oposite of the above. Does nothing if AForm.Tag is $FFFFF. }
procedure FormToObject(AForm: TForm; AObject: TObject);

{ Sets ARTIProp.Value to the user changable property of the AControl }
function RTIPropToControl(ARTIProp: TRTIProp; AControl: TControl): boolean;

{ Sets user changable property of the AControl to ARTIProp.Value }
function ControlToRTIProp(AControl: TControl; ARTIProp: TRTIProp): boolean;

implementation

function FindProp(AFormComp: TComponent; rti: TRTIObj; var AProp: TRTIProp): boolean;
var
  i: integer;
  n: string;
begin
  Result := false;
  for i := 0 to rti.PropCount - 1 do begin
    n := rti.Props[i].Name;
    if pos(n, AFormComp.Name) = 1 then begin
      if (AFormComp.Name = n)
         or
         (
         (length(AFormComp.Name) > length(n)) and (AFormComp.Name[length(n)+1] = '_')
         )
      then begin
        AProp := rti.Props[i];
        Result := true;
        break;
      end;
    end;
  end;
end;

procedure FormToObject(AForm: TForm; AObject: TObject);
var
  c: TComponent;
{  v: string;}
  i: integer;
{  j: integer;}
{  buffer: PChar;
  size: integer;}

  {v0.61}
  rti: TRTIObj;
  rtip: TRTIProp;
  {/v0.61
  n: string;
  pi: PPropInfo;}

begin
  if (AForm = nil) or (AObject = nil) then
    exit;
  if AForm.Tag = $FFFF then { is in ObjectToForm call }
    exit;
  rti := TRTIObj.Create(nil);
  try
    rti.Obj := AObject;
    for i := 0 to AForm.ComponentCount - 1 do begin
      c := AForm.Components[i];
      if not FindProp(c, rti, rtip) then
        continue;
        { no property with name that is left substring of the current
          form component c was found, so try next one }
      if c is TControl then
        ControlToRTIProp(TControl(c), rtip);
    end;
  finally
    rti.Free;
  end;
end;


procedure ObjectToForm(AObject: TObject; AForm: TForm);
var
  c: TComponent;
  i: integer;
{  j: integer;}
  origTag: integer;
  rti: TRTIObj;
  rtip: TRTIProp;
begin
  if (AForm = nil) or (AObject = nil) then
    exit;
  {v0.61}
  rti := TRTIObj.Create(nil);
  origTag := AForm.Tag;
  AForm.Tag := $FFFF;
  try
    rti.Obj := AObject;
    for i := 0 to AForm.ComponentCount - 1 do begin
      c := AForm.Components[i];
      if not FindProp(c, rti, rtip) then
        continue;
        { no property with name that is left substring of the current
          form component c was found, so try next one }
      if c is TControl then
        RTIPropToControl(rtip, TControl(c));
    end;
  finally
    AForm.Tag := origTag;
    rti.Free;
  end;
end;

{v0.61}
{ Sets ARTIProp.Value to the user changable property of the AControl }
function RTIPropToControl(ARTIProp: TRTIProp; AControl: TControl): boolean;
var
{  buffer: PChar;
  size: integer;}
  v: string;
  rti: TRTIObj;
  rtip: TRTIProp;
begin
  Result := true;
  v := ARTIProp.Value;
  if AControl is TEdit then begin
    with AControl as TEdit do begin
      Text := v;
    end;
  end else if AControl is TComboBox then begin
    with AControl as TComboBox do begin
      if Items.Count = 0 then
        ARTIProp.FillEnumNames(Items);
      if Style = csDropDownList then begin
        ItemIndex := Items.IndexOf(v);
      end else
        Text := v;
    end;
  end else if AControl is TCheckBox then begin
    with AControl as TCheckBox do begin
      Checked := (v = 'True');
    end;
  end else if AControl is TMemo then begin
    with AControl as TMemo do begin
      Lines.Clear;
      SelText := v;
    end;
  end else begin
    rti := TRTIObj.Create(nil);
    try
      rti.Obj := AControl;
      if rti.HasProp('Text', rtip) then begin
        rtip.Value := v;
      end else if rti.HasProp('Value', rtip) then begin
        rtip.Value := v;
      end else
        Result := false;
    finally
      rti.Free;
    end;
  end;
end;
{ Sets user changable property of the AControl to ARTIProp.Value }
function ControlToRTIProp(AControl: TControl; ARTIProp: TRTIProp): boolean;
var
  v: string;
  buffer: PChar;
  size: integer;
  rti: TRTIObj;
  rtip: TRTIProp;
begin
  Result := true;
  if AControl is TEdit then begin
    with AControl as TEdit do begin
      v := Text;
    end;
  end else if AControl is TComboBox then begin
    with AControl as TComboBox do begin
      v := Text;
    end;
  end else if AControl is TCheckBox then begin
    with AControl as TCheckBox do begin
      if Checked then
        v := 'True'
      else
        v := 'False';
    end;
  end else if AControl is TMemo then begin
    with AControl as TMemo do begin
      SelectAll;
      Size := SelLength + Lines.Count * 2 + 1;
      GetMem(Buffer, Size);
      try
        GetSelTextBuf(Buffer, Size);
        v := StrPas(Buffer);
      finally
        FreeMem(Buffer, Size);
      end;
    end;
  end else begin
    rti := TRTIObj.Create(nil);
    try
      rti.Obj := AControl;
      if rti.HasProp('Text', rtip) then begin
        v := rtip.Value;
      end else if rti.HasProp('Value', rtip) then begin
        v := rtip.Value
      end else begin
        Result := false;
        exit;
      end;
    finally
      rti.Free;
    end;
  end;
  ARTIProp.Value := v;
end;
{/v0.61}

end.
