unit MMMainFrm;
{------------------------------------------------------------------------------}
{
  Very simple "mail merging" application (LabelItem Version).
  It loads a template from TEMPLATE.RVF, and data from CUSTOMERS.TXT.
  Template can be modified with another application in this directory:
  TEMPLATEEDITORLI.

  Main settings:
  - since field names are stored in tags (see the help topic about tags)
    as strings, rvoTagsArePChars is included in Options of rvTemplate and
    rvOutput.
  - fields are represented with LabelItem item type.
  - rvOutput.Style = rvsOutput, rvTemplate.Style = rvsTemplate.
    In rvOutput, fields are not highlighted, in rvTemplate they are always
    highlighted.
}
{------------------------------------------------------------------------------}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  Dialogs, RVScroll, RichView, StdCtrls, RVStyle, RVTable, CRVData,
  RVLabelItem, RVSeqItem;

type
  TfrmMainMerge = class(TForm)
    ListBox1: TListBox;
    rvOutput: TRichView;
    rvsOutput: TRVStyle;
    rvsTemplate: TRVStyle;
    rvTemplate: TRichView;
    Label1: TLabel;
    Label2: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure ListBox1Click(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    Codes: TStringList;
    procedure LoadCustomers;
    function IsFieldCode(const FieldName: String): Boolean;
    function GetFieldValueFromDatabase(const FieldName: String): String;
    procedure FillFields(RVData: TCustomRVData);
  public
    { Public declarations }
  end;

var
  frmMainMerge: TfrmMainMerge;

implementation

{$R *.dfm}

{ TForm1 }

{------------------------------------------------------------------------------}
{ This procedure loads file CUSTOMERS.TXT into:
  - ListBox1.Items (<- names of customers)
  - Codes (<- codes of customers)
  In real applications data can be stored in some database }
procedure TfrmMainMerge.LoadCustomers;
var F: TextFile;
    i, Count: Integer;
    s: String;
begin
  AssignFile(F, ExtractFilePath(Application.ExeName)+'Customers.txt');
  Reset(F);
  try
    Readln(F, Count);
    for i := 0 to Count-1 do
    begin
      Readln(F, s);
      Codes.Add(s);
      Readln(F, s);
      ListBox1.Items.Add(Trim(s))
    end;
  finally
    CloseFile(F);
  end;
end;
{------------------------------------------------------------------------------}
{ Initialization: loading template into rvOutput, loading customers data. }
procedure TfrmMainMerge.FormCreate(Sender: TObject);
begin
  Codes := TStringList.Create;
  LoadCustomers;
  rvTemplate.LoadRVF(ExtractFilePath(Application.ExeName)+'template.rvf');
  rvTemplate.Format;
  if ListBox1.Items.Count>0 then
  begin
    ListBox1.ItemIndex := 0;
    ListBox1.OnClick(nil);
  end;
end;
{------------------------------------------------------------------------------}
procedure TfrmMainMerge.FormDestroy(Sender: TObject);
begin
  Codes.Free;
  Codes := nil;
end;
{------------------------------------------------------------------------------}
{ Returns True if FieldName is a valid field code }
function TfrmMainMerge.IsFieldCode(const FieldName: String): Boolean;
begin
  Result := (FieldName='name') or (FieldName='code') or
    (Copy(FieldName, 1, 5)='date:');
end;
{------------------------------------------------------------------------------}
{ This function returns the current field value by the field name.
  In this example, we have two data fields: "name" and "code",
  and "date" field }
function TfrmMainMerge.GetFieldValueFromDatabase(const FieldName: String): String;
var Index: Integer;
begin
  Index := ListBox1.ItemIndex;
  if FieldName='name' then
    Result := ListBox1.Items[Index]
  else if FieldName='code' then
    Result := Codes[Index]
  else if Copy(FieldName, 1, 5)='date:' then begin
    Result := Copy(FieldName, 6, Length(FieldName));
    Result := DateToStr(StrToFloat(Result));
    end
  else
    Result := '{error: illegal field code}';
end;
{------------------------------------------------------------------------------}
{ This function iterates through all items in RVData, and if tag of
  some label item is a data field, it calls GetFieldValueFromDatabase(tag)
  and replaces the label item's text with the returned value.
  You can move this function to your application unchanged.
  Initial call: FillFields(RichView.RVData); }
procedure TfrmMainMerge.FillFields(RVData: TCustomRVData);
var i,r,c: Integer;
    table: TRVTableItemInfo;
    FieldName: String;
begin
  for i := 0 to RVData.ItemCount-1 do
    case RVData.GetItemStyle(i) of
      rvsTable:
        begin
          table := TRVTableItemInfo(RVData.GetItem(i));
          for r := 0 to table.RowCount-1 do
            for c := 0 to table.ColCount-1 do
              if table.Cells[r,c]<>nil then
                FillFields(table.Cells[r,c].GetRVData);
        end;
      rvsLabel:
        begin
          FieldName := PChar(RVData.GetItemTag(i));
          if IsFieldCode(FieldName) then
            TRVLabelItemInfo(RVData.GetItem(i)).Text := GetFieldValueFromDatabase(FieldName);
        end;
    end;
end;
{------------------------------------------------------------------------------}
{ On highlighting a new list box item: updating document in rvOutput. }
procedure TfrmMainMerge.ListBox1Click(Sender: TObject);
begin
  rvOutput.Clear;
  if ListBox1.ItemIndex>=0 then
  begin
    rvOutput.LoadRVF(ExtractFilePath(Application.ExeName)+'template.rvf');
    FillFields(rvOutput.RVData);
    rvOutput.Format;
  end;
end;



end.
