{
        Пример работы с отчетами Rave Report в режиме RunTime

Примеры работы с технологией RTTI были позаимствованы и несколько изменены
из книги Стива Тейксейра и Ксавье Пачеко "DELPHI 5 Руководство разработчика.
Том 2. Разработка компонентов и работа с базами данных".

Для работы программы необходимо вложить демонстрационный отчет "RaveDemo.rav"
поставляемый с Rave Report в каталог программы. В примере используется
БД MS Access "Test.mdb" соединение с которой осуществляется средствами технологии ADO.
Для настройки соединения необходимо отредактировать файл "Test.udl".

Турушев Виталий (Sun bittern ©).
Нижний Тагил 2004г.
Sun-bittern@Mail.ru

}

unit MainRTR;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, RpBase, RpSystem, RpDefine, RpRave, RvCsDraw, RvCsBars, RvCsStd,
  RvCsRpt, RvCsData, RvProj, RvClass, StdCtrls, Buttons, Menus, ExtCtrls, RvData,
  RvDirectDataView, RvDataField, RpCon, RvDefine, ActnList, StdActns, DB,
  ADODB, RpConDS;

type
  TFormRTR = class(TForm)
    RvProjectRTR: TRvProject;
    RvSystemRTR: TRvSystem;
    MemoInfo: TMemo;
    MainMenu1: TMainMenu;
    Reports: TMenuItem;
    ReplaceText: TMenuItem;
    Panel1: TPanel;
    ListReport: TListBox;
    ListObjects: TListBox;
    Splitter1: TSplitter;
    Splitter2: TSplitter;
    ListProperty: TListBox;
    Splitter3: TSplitter;
    MirrorReport1: TMenuItem;
    ImitationVisible: TMenuItem;
    NewReports: TMenuItem;
    ImitationBrushColor: TMenuItem;
    CreateNewReport: TMenuItem;
    ClearPageList: TMenuItem;
    ViewReport: TMenuItem;
    ShowActiveReport: TMenuItem;
    estSaverav1: TMenuItem;
    ActionList1: TActionList;
    aReplaceText: TAction;
    aImitationVisible: TAction;
    aImitationBrushColor: TAction;
    aCreateNewReport: TAction;
    aViewReport: TAction;
    aClearPageList: TAction;
    aShowActiveReport: TAction;
    aSaveRave: TAction;
    aConectDB: TAction;
    FileExit1: TFileExit;
    N2: TMenuItem;
    ConectDB: TMenuItem;
    ADOConnectionRTR: TADOConnection;
    RvDataSetConnectionRTR: TRvDataSetConnection;
    ADOTableRTR: TADOTable;
    ADOTableRTRFieldInt: TIntegerField;
    ADOTableRTRFieldStr: TWideStringField;
    procedure FormCreate(Sender: TObject);
    procedure ListReportClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure ListObjectsClick(Sender: TObject);
    procedure ListPropertyClick(Sender: TObject);
    procedure aReplaceTextUpdate(Sender: TObject);
    procedure aReplaceTextExecute(Sender: TObject);
    procedure aImitationVisibleExecute(Sender: TObject);
    procedure aImitationBrushColorExecute(Sender: TObject);
    procedure aCreateNewReportExecute(Sender: TObject);
    procedure aViewReportExecute(Sender: TObject);
    procedure aClearPageListExecute(Sender: TObject);
    procedure aShowActiveReportExecute(Sender: TObject);
    procedure aSaveRaveExecute(Sender: TObject);
    procedure aConectDBExecute(Sender: TObject);
    procedure aViewReportUpdate(Sender: TObject);
    procedure aConectDBUpdate(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    procedure ShowListObject;
  end;

var
  FormRTR: TFormRTR;

implementation

{$R *.dfm}

uses
  TypInfo;

const
  FileReport  = 'RaveDemo.rav';      // Имя файла проекта отчета
  NewRep      = 'MyNewReport';       // Имя отчета (динамически создаваемого)
  FieldStr    = 'FieldStr';          // Имя строкового поля
  FieldInt    = 'FieldInt';          // Имя целочисленного поля
  NewDataView = 'NewDataView';       // Имя компонента для посредника с источником данных

// Вычисление позиции точки в процентах относительно ширины/высоты визуального компонента
function SetPointInPercent(RaveControlWH: TRaveUnits; Percent: Byte): TRaveUnits;
begin
  Result := (RaveControlWH / 100) * Percent;
end;

// извлечение списка имен объектов и имен классов родительских компонентов,
// компонента ClassX: TComponent
procedure GetListObjects(ListClass: TStrings; ClassX: TComponent; TabStr: String; AddObjects: Boolean = False);
  var
    I: Integer;
begin
  if (ClassX = NIL) or (ListClass = NIL) then EXIT;
  for I := 0 to ClassX.ComponentCount - 1 do
  begin
    if AddObjects then
      ListClass.AddObject(TabStr + ClassX.Components[I].Name +
        ' - ' + ClassX.Components[I].ClassName, ClassX.Components[I])
    else ListClass.Add(TabStr + ClassX.Components[I].Name +
        ' - ' + ClassX.Components[I].ClassName);
    if ClassX.Components[I].ComponentCount > 0 then
      GetListObjects(ListClass, ClassX.Components[I], TabStr + '..', AddObjects);
  end;
end;

// Извлечение списка имен классов предков,
// класса ClassX: TClass
procedure GetListParentClassName(ListClass: TStrings; ClassX: TClass; ClearList: Boolean = True);
begin
  if (ClassX = NIL) or (ListClass = NIL) then EXIT;
  if ClearList then ListClass.Clear;
  while ClassX <> NIL do
  begin
    ListClass.Add(ClassX.ClassName);
    ClassX := ClassX.ClassParent;
  end;
end;

// Возвращает список объектов, порожденных от указанного класса FindClass
procedure GetObjectList(RootComponent: TComponent; FindClass: TClass; var PageList: TList);
  var
    I: Integer;
begin
  if (RootComponent = NIL) or (PageList = NIL) then EXIT;
  PageList.Clear;
  for I := 0 to RootComponent.ComponentCount - 1 do
    if RootComponent.Components[I] is FindClass then PageList.Add(RootComponent.Components[I]);
end;

// Извлечение базовой информации об объекте
procedure GetListClassInfo(ListInfo: TStrings; ClassX: TObject; ClearList: Boolean = True);
var
  // В данные структуры записывается информация об RTTI объекта
  Class_PTI: PTypeInfo;
  Class_PTD: PTypeData;
begin
  if (ClassX = NIL) or (ListInfo = NIL) then EXIT;
  if ClearList then ListInfo.Clear;
  // Получение информации об RTTI объекта
  Class_PTI := ClassX.ClassInfo;
  Class_PTD := GetTypeData(Class_PTI);
  // Вывод базовой информации об объекте
  with ListInfo do
  begin
    Add('Базовая информация:');
    Add(Format('Имя класса:                 %s', [Class_PTI.Name]));
    Add(Format('Тип класса:                 %s', [GetEnumName(TypeInfo(TTypeKind), Integer(Class_PTI.Kind))]));
    Add(Format('Размер объекта:             %d', [ClassX.InstanceSize]));
    Add(Format('Описан в модуле:            %s', [Class_PTD.UnitName]));
    Add(Format('Всего доступно свойств:     %d', [Class_PTD.PropCount]));
    if ClassX is TRaveControl then
    begin
      Add('Родительский компонент:');
      Add(Format('Тип класса:     %s', [TRaveControl(ClassX).Parent.ClassName]));
      Add(Format('Имя компонента: %s', [TRaveControl(ClassX).Parent.Name]));
    end;
    Add('Генеалогическое дерево класса:');
    // Вывод информации о предках объекта
    GetListParentClassName(ListInfo, ClassX.ClassType, False);
  end;
end;

// Извлечение информации о наименовании свойств и событий объекта
procedure GetListProperty(ListPropertys: TStrings; ClassX: TObject; AddObjects: Boolean = False; ClearList: Boolean = True);
var
  PropList: PPropList;
  Class_PTI: PTypeInfo;
  Class_PTD: PTypeData;
  I, PropertyCount: Integer;
  S, StrVal: String;
  TmpObj: TObject;
begin
  if (ClassX = NIL) or (ListPropertys = NIL) then EXIT;
  if ClearList then ListPropertys.Clear;
  Class_PTI := ClassX.ClassInfo;
  Class_PTD := GetTypeData(Class_PTI);
  if Class_PTD.PropCount <> 0 then
  begin
    // Выделение памяти под структуры TPropInfo, в зависимости от количества свойств объекта
    GetMem(PropList, SizeOf(PPropInfo) * Class_PTD.PropCount);
    try
      // Заполнение PropList указателями на структуры TPropInfo
      GetPropInfos(ClassX.ClassInfo, PropList);
      for I := 0 to Class_PTD.PropCount - 1 do
        // Добавляются свойства не являющиеся событиями
        if not (PropList[I]^.PropType^.Kind = tkMethod) then
        begin
          // Извлечение текущего значения свойства
          if PropList[I]^.PropType^.Kind = tkClass then
          begin
            TmpObj := GetObjectProp(ClassX, PropList[I]^.Name);
            if TmpObj = NIL then StrVal := 'NIL' else
              // Если у объекта есть предок TComponent, то извлекается имя объекта иначе имя класса
              if TmpObj is TComponent then StrVal := TComponent(TmpObj).Name else StrVal := '(' + TmpObj.ClassName + ')';
          end else StrVal := GetPropValue(ClassX, PropList[I]^.Name);
          S := Format('%s: %s = %s', [PropList[I]^.Name, PropList[I]^.PropType^.Name, StrVal]);
          if AddObjects then ListPropertys.AddObject(S, TObject(PropList[I]^.PropType^))
            else ListPropertys.Add(S);
        end;
      // Поиск свойств-событий
      PropertyCount := GetPropList(ClassX.ClassInfo, [tkMethod], PropList);
        ListPropertys.Add('*** Свойства-события ***');
      // Добавляются свойства-события
      for i := 0 to PropertyCount - 1 do
        begin
          S := Format('%s: %s', [PropList[I]^.Name, PropList[I]^.PropType^.Name]);
          if AddObjects then ListPropertys.AddObject(S, TObject(PropList[I]^.PropType^))
            else ListPropertys.Add(S);
        end;
    finally
      // Освобождение ранее выделенной памяти
      FreeMem(PropList, SizeOf(PPropInfo) * Class_PTD.PropCount);
    end;
  end;
end;

// Извлечение информации о свойствах и методах объекта
procedure GetPropertyInfo(ListInfo: TStrings; PTI: PTypeInfo; PTD: PTypeData; ClearList: Boolean = True);
  type
    // Структура для извлечения информации из методов (свойства-события)
    PParamRec = ^TParamRec;
    TParamRec = packed record
      Flags: TParamFlags;
      ParamName: ShortStringBase;
      TypeName: ShortStringBase;
    end;
  var
    I: Integer;
    S, S2: String;
    TeStr,
    RStr: ^ShortStringBase;
    ParamRec: PParamRec;
  // Базовая информация для всех свойств
  Procedure Name_Info;
  begin
    ListInfo.Add(Format('Тип свойства:          %s', [PTI.Name]));
    ListInfo.Add(Format('Подтип свойства:       %s', [GetEnumName(TypeInfo(TTypeKind), Integer(PTI^.Kind))]));
  end;
  // Информация для целочисленных, множеств и перечисляемых типов свойств
  procedure Int_Info;
  begin
    ListInfo.Add(Format('Минимальное значение:  %d', [PTD^.MinValue]));
    ListInfo.Add(Format('Максимальное значение: %d', [PTD^.MaxValue]));
  end;
  // Информация для типов свойств с плавающей точкой
  procedure Float_Info;
  begin
    // Определение подтипа свойства
    case PTD^.FloatType of
      ftSingle:   S := 'ftSingle';
      ftDouble:   S := 'ftDouble';
      ftExtended: S := 'ftExtended';
      ftComp:     S := 'ftComp';
      ftCurr:     S := 'ftCurr';
    end;
    ListInfo.Add(Format('Подтип tkFloat:        %s', [S]));
    ListInfo.Add('Минимальное значение:  ' + FloatToStr(PTD^.MinInt64Value));
    ListInfo.Add('Максимальное значение: ' + FloatToStr(PTD^.MaxInt64Value));
  end;
  // Информация для свойства представленного как класс
  procedure Class_Info;
  begin
    ListInfo.Add(Format('Предок класса свойства:        %s', [PTD^.ParentInfo^.Name]));
    ListInfo.Add(Format('Доступно свойств у объекта:    %d', [PTD^.PropCount]));
    ListInfo.Add(Format('Описан в модуле:               %s', [PTD^.UnitName]));
  end;
  // Информация для методов (свойства-события)
  procedure Method_Info;
    var
      J: Integer;
  begin
    // Определение типа метода
    case PTD^.MethodKind of
      mkProcedure:      S := 'Procedure ';
      mkFunction:       S := 'Function ';
      mkConstructor:    S := 'Constructor ';
      mkDestructor:     S := 'Destructor ';
      mkClassProcedure: S := 'ClassProcedure ';
      mkClassFunction:  S := 'ClassFunction ';
      mkSafeProcedure:  S := 'SafeProcedure ';
      mkSafeFunction:   S := 'SafeFunction ';
    end;
    // Извлечение информации о передаваемом параметре
    ParamRec := @PTD^.ParamList;
    J := 1;
    ListInfo.Add(Format('Передаваемых параметров:        %d', [PTD^.ParamCount]));
    while J <= PTD^.ParamCount do
    begin
      if J = 1 then S := S + '(';
      // Определение метода передачи параметра
      if pfVar in ParamRec.Flags then S2 := 'var ';
      if pfConst in ParamRec.Flags then S2 := 'const ';
      if pfArray in ParamRec.Flags then S2 := 'array of ';
      if pfOut in ParamRec.Flags then S2 := 'out ';
      // Извлечение информации о типе передаваемого параметра
      TeStr := Pointer(Integer(@ParamRec^.ParamName) + Length(ParamRec^.ParamName) + 1);
      S := S + S2;
      S := Format('%s%s: %s', [S, ParamRec^.ParamName, TeStr^]);
      Inc(J);
      // Извлечение информации о следующем передаваемом параметре
      ParamRec := PParamRec(Integer(ParamRec) + SizeOf(TParamFlags) +
        (Length(ParamRec^.ParamName) + 1) + (Length(TeStr^) + 1));
      if J > PTD^.ParamCount then S := S + ')';
      // Если метод является функцией, то извлекается информация о возвращаемом параметре
      if PTD^.MethodKind = mkFunction then
      begin
        RStr := Pointer(ParamRec);
        S := Format('%s: %s;', [S, RStr^]);
      end else S := S + '; ';
    end;
    ListInfo.Add(S);
  end;
  // Вывод информации для типа строковых свойств
  procedure Str_Info;
  begin
    ListInfo.Add(Format('Максимальная длина:  %d', [PTD^.MaxLength]));
  end;
begin
  if (ListInfo = NIL) or (PTI = NIL) or (PTD = NIL) then EXIT;
  if ClearList then ListInfo.Clear;
  Name_Info;
  // Извлечение информации для свойств множеств
  if PTI^.Kind = tkSet then
  begin
    PTI := PTD^.CompType^;
    PTD := GetTypeData(PTI);
    Name_Info;
  end;

  case PTI^.Kind of
    tkInteger: Int_Info;
    tkFloat: Float_Info;
    tkString: Str_Info;
    tkLString: Str_Info;
    tkWString: Str_Info;
    // Извлечение информации для перечисляемых свойств
    tkEnumeration:
    begin
      Int_Info;
      ListInfo.Add('Варианты значений:');
      for I := PTD^.MinValue to PTD^.MaxValue do
        ListInfo.Add(Format('Значение: %s', [GetEnumName(PTI, I)]));
    end;
    tkClass: Class_Info;
    tkMethod: Method_Info;
  end;
end;

procedure TFormRTR.FormCreate(Sender: TObject);
begin
  // Задается компонент управляющий отчетом
  RvProjectRTR.Engine := RvSystemRTR;
  if FileExists(FileReport) then
  begin
    // Присваивается имя файла отчета
    RvProjectRTR.ProjectFile := 'RaveDemo.rav';
    // Открытие отчета
    RvProjectRTR.Open;
  end else raise Exception.Create('Нет файла "RaveDemo.rav" в каталоге программы!');
end;

// Вывод списка объектов в активном отчете
procedure TFormRTR.ShowListObject;
begin
  ListObjects.Clear;
  GetListObjects(ListObjects.Items, RvProjectRTR.ProjMan.ActiveReport, '', True);
  if ListObjects.Items.Count > 0 then
    ListObjects.Selected[0] := True;
  ListObjectsClick(NIL);
end;

// Выбор отчета из списка
procedure TFormRTR.ListReportClick(Sender: TObject);
begin
  RvProjectRTR.SelectReport(ListReport.Items[ListReport.ItemIndex], True);
  ShowListObject;
end;

procedure TFormRTR.FormShow(Sender: TObject);
begin
  // Вывод списка доступных отчетов
  if not RvProjectRTR.Active then raise Exception.Create('Проект отчета "RaveDemo.rav" не загружен!');
  RvProjectRTR.GetReportList(ListReport.Items, True);
  if ListReport.Items.Count > 0 then ListReport.Selected[0] := True;
  ShowListObject;
end;

// Вывод информации об объекте и его свойствах активного отчета
procedure TFormRTR.ListObjectsClick(Sender: TObject);
begin
  if ListObjects.Items.Objects[ListObjects.ItemIndex] <> NIL then
  begin
    GetListClassInfo(MemoInfo.Lines, ListObjects.Items.Objects[ListObjects.ItemIndex]);
    GetListProperty(ListProperty.Items, ListObjects.Items.Objects[ListObjects.ItemIndex], True);
  end;
end;

// Вывод информации о свойстве объекта (RTTI)
procedure TFormRTR.ListPropertyClick(Sender: TObject);
  var
    TI: PTypeInfo;
    TD: PTypeData;
begin
  if ListProperty.Items.Objects[ListProperty.ItemIndex] = NIL then EXIT;
  TI := PTypeInfo(ListProperty.Items.Objects[ListProperty.ItemIndex]);
  TD := GetTypeData(TI);
  GetPropertyInfo(MemoInfo.Lines, TI, TD);
end;

procedure TFormRTR.aReplaceTextUpdate(Sender: TObject);
begin
  if Sender is TAction then
    if RvProjectRTR.Active then TAction(Sender).Enabled := True else TAction(Sender).Enabled := False;
end;

// Смена текста у компонента TRaveText
procedure TFormRTR.aReplaceTextExecute(Sender: TObject);
  var
    TmpRaveComponent: TRaveComponent;
begin
  // Поиск и активизация необходимого отчета. Метод вернет false если отчет не найден
  if not RvProjectRTR.SelectReport('Mirror Report', true) then EXIT;
  // Поиск компонента с именем 'Text1' на первой странице отчета
  TmpRaveComponent := RvProjectRTR.ProjMan.FindRaveComponent('Text1', RvProjectRTR.ProjMan.ActiveReport.FirstPage);
  // Если объект найден и он произощел от класса TRaveText
  if (TmpRaveComponent <> NIL) and (TmpRaveComponent is TRaveText) then
  begin
    // Замена выводимого текста
    TRaveText(TmpRaveComponent).Text := 'Это мой новый заголовок';
    // Изменение стиля шрифта
    TRaveText(TmpRaveComponent).Font.Style := [fsItalic];
  end;
  // Генерация активного отчета
  RvProjectRTR.Execute;
end;

// Имитация скрытия компонентов TRaveRectangle
procedure TFormRTR.aImitationVisibleExecute(Sender: TObject);
  var
    I: Integer;
    TmpRaveComponent: TRaveComponent;
begin
  // Поиск и активизация необходимого отчета. Метод вернет false если отчет не найден
  if not RvProjectRTR.SelectReport('Mirror Report', true) then EXIT;
  // Проход по всем объектам первой страницы отчета
  for I := 0 to RvProjectRTR.ProjMan.ActiveReport.FirstPage.ComponentCount - 1 do
    // Если объект является TRaveSection
    if RvProjectRTR.ProjMan.ActiveReport.FirstPage.Components[I] is TRaveSection then
    begin
      TmpRaveComponent := TRaveComponent(RvProjectRTR.ProjMan.ActiveReport.FirstPage.Components[I]);
      // Если данный объект не имеет родителя, то в качестве родителя указывается первая страница отчета
      if TmpRaveComponent.Parent = NIL then
        TmpRaveComponent.Parent := RvProjectRTR.ProjMan.ActiveReport.FirstPage
          // Если объект имеет родителя, то уничтожается ссылка на родителя, что в следствии приводит к скрытию объекта
          else TmpRaveComponent.Parent := NIL;
    end;
  // Генерация активного отчета
  RvProjectRTR.Execute;
end;

// Имитация фонового цвета
procedure TFormRTR.aImitationBrushColorExecute(Sender: TObject);
  var
    TmpRaveComponent: TRaveComponent;
    TmpRavePage: TRavePage;
    BGRect: TRaveRectangle;
begin
  // Поиск и активизация необходимого отчета. Метод вернет false если отчет не найден
  if not RvProjectRTR.SelectReport('Mirror Report', true) then EXIT;
  TmpRavePage := RvProjectRTR.ProjMan.ActiveReport.FirstPage;
  // Поиск компонента с именем 'Text1' на первой странице отчета
  TmpRaveComponent := RvProjectRTR.ProjMan.FindRaveComponent('Text1', TmpRavePage);
  // Если объект найден и он произошел от класса TRaveText
  if (TmpRaveComponent <> NIL) and (TmpRaveComponent is TRaveText) then
  begin
    // Создание графического примитива - прямоугольник
    BGRect := TRaveRectangle.Create(TmpRavePage);
    // Заполнение свойств вновь созданного объекта
    with BGRect do
    begin
      Name := 'BackGroundRect';
      FillColor := clYellow;
      BorderStyle := psClear;
      // Указание родителя компонента
      Parent := TmpRavePage;
      // Подгонка размеров прямоугольника под размеры компонента TRaveText
      BoundsRect := TRaveText(TmpRaveComponent).BoundsRect;
      // Перемещение объекта на задний план
      SendToBack;
    end;
  end;
  // Генерация активного отчета
  RvProjectRTR.Execute;
end;

// Создание нового отчета
procedure TFormRTR.aCreateNewReportExecute(Sender: TObject);
  const
    Picture = '1.bmp';
  var
    TmpRaveReport: TRaveReport;
    TmpRavePage: TRavePage;
    TmpRaveText: TRaveText;
    TmpRaveBitMap: TRaveBitmap;
    TmpPageList: TRaveComponentList;
begin
  // Если отчет уже создан, то выходим
  if RvProjectRTR.SelectReport(NewRep, true) then EXIT;
  // Добавление нового отчета в проект и заполнение его свойств
  TmpRaveReport := RvProjectRTR.ProjMan.NewReport;
  with TmpRaveReport do
  begin
    Name := NewRep;
    FullName := NewRep;
    // Создание новой страницы для отчета (здесь будет графическое изображение)
    TmpRavePage := NewPage;
    // Указывается следующая страница для генерации отчета,
    // после того, как будет сгенерированна первая страница отчета
    TmpRaveReport.FirstPage.GotoPage := TmpRavePage;
  end;
  // Создание компонента для вывода графического изображения и заполнение его свойств
  TmpRaveBitMap := TRaveBitMap.Create(TmpRavePage);
  with TmpRaveBitMap do
  begin
    Name := 'MyNewRaveBitMap';
    Left := SetPointInPercent(TmpRavePage.PageWidth, 5);
    Top := SetPointInPercent(TmpRavePage.PageHeight, 20);
    Width := SetPointInPercent(TmpRavePage.PageWidth, 30);
    Height := SetPointInPercent(TmpRavePage.PageHeight, 30);
    // Загрузка графического изображения (если найден указанный файл)
    if FileExists(Picture) then Image.LoadFromFile(Picture);
    // Размеры изображения будут подогнаны под клиентские размеры компонента
    MatchSide := msBoth;
    // Родителем данного компонента будет страница TmpRavePage
    Parent := TmpRavePage;
  end;
  // Создание элемента TRaveText и заполнение его свойств
  TmpRaveText := TRaveText.Create(TmpRaveReport.FirstPage);
  with TmpRaveText do
  begin
    Left := SetPointInPercent(TmpRaveReport.FirstPage.PageWidth, 10);;
    Top := SetPointInPercent(TmpRaveReport.FirstPage.PageHeight, 15);;
    Font.Size := 18;
    Name := 'MyNewRaveText';
    // Родителем данного объекта будет первая страница отчета
    Parent := TmpRaveReport.FirstPage;
    Text := 'Этот текст расположен на первой странице отчета';
  end;
  // Заполение свойств страницы TmpRavePage
  with TmpRavePage do
  begin
    Name := 'MyNewRavePage';
    FullName := 'Моя новая страница';
  end;
  // Создание списка генерируемых страниц
  TmpPageList := TRaveComponentList.Create;
  TmpPageList.Add(TmpRavePage);
  TmpPageList.Add(TmpRaveReport.FirstPage);
  TmpRaveReport.PageList := TmpPageList;
  // Обновление списка доступных отчетов
  RvProjectRTR.GetReportList(ListReport.Items, True);
end;

// Поиск и генерация вновь созданного отчета
procedure TFormRTR.aViewReportExecute(Sender: TObject);
begin
  if RvProjectRTR.SelectReport(NewRep, true) then RvProjectRTR.Execute;
end;

// Поиск и генерация нового отчета (с пустым списком "PageList")
procedure TFormRTR.aClearPageListExecute(Sender: TObject);
begin
  if RvProjectRTR.SelectReport(NewRep, true) then
  begin
    RvProjectRTR.ProjMan.ActiveReport.PageList := NIL;
    RvProjectRTR.Execute;
  end;
end;

// Генерация активного отчета из списка отчетов
procedure TFormRTR.aShowActiveReportExecute(Sender: TObject);
begin
  RvProjectRTR.Execute;
end;

// Сохраниение проекта отчета под именем 'TestSave.rav'
procedure TFormRTR.aSaveRaveExecute(Sender: TObject);
begin
  RvProjectRTR.SetProjectFile('TestSave.rav');
  RvProjectRTR.Save;
end;

// Присоеденить источник данных
procedure TFormRTR.aConectDBExecute(Sender: TObject);
  var
    TmpRaveReport: TRaveReport;
    TmpDataView: TRaveDataView;
    TmpDataField: TRaveDataField;
    TmpRaveRegion: TRaveRegion;
    TmpRaveDataBand: TRaveDataBand;
    TmpRaveDataText: TRaveDataText;
    TmpField: TField;
begin
  TmpDataField := NIL;
  if not RvProjectRTR.SelectReport(NewRep, true) then EXIT;
  try
    with ADOConnectionRTR do
    begin
      ConnectionString := 'FILE NAME=Test.udl';
      Open;
      ADOTableRTR.Open;
    end;
  except
    MessageDlg('Ошибка при поключении к БД. Убедитесь, что в каталоге программы' + #13 +
    'есть файлы "Test.udl" и "Test.mdb". Так же попробуйте заново задать настройки в файле "Test.udl"',
    mtError, [mbOK], 0);
  end;

  if (ADOTableRTR.FieldCount < 1) or (not ADOTableRTR.Active) then EXIT;
  // Поиск строкового поля
  TmpField := RvDataSetConnectionRTR.DataSet.FindField(FieldStr);
  if TmpField = NIL then EXIT;
  TmpRaveReport := RvProjectRTR.ProjMan.ActiveReport;
  // Создание TRaveDataView обеспечивающий работу с источником данных
  TmpDataView := TRaveDataView.Create(RvProjectRTR.ProjMan);
  RvProjectRTR.ProjMan.DataObjectList.Add(TmpDataView);
  with TmpDataView do
  begin
    Name := NewDataView;
    Parent := RvProjectRTR.ProjMan;
    DataCon.Connection := RvDataSetConnectionRTR;
    ConnectionName := TmpDataView.DataCon.Connection.Name;
  end;
  // В зависимости от типа данных поля создается поле данных для отчета
  // Rave Report соотвествующего типа
  case TmpField.DataType of
    ftString,
    ftWideString: TmpDataField := TRaveStringField.Create(TmpDataView);
    ftInteger:    TmpDataField := TRaveIntegerField.Create(TmpDataView);
  end;
  if TmpDataField = NIL then EXIT;
  // Заполение свойств поля данных
  with TmpDataField do
  begin
    Name := TmpField.Name;            // Имя компонента
    FieldName := TmpField.FieldName;  // Имя поля
    FullName := TmpField.DisplayName; // Альтернативное имя поля
    DataIndex := TmpField.Index;      // Порядковый номер в списке полей источника данных (таблице)
    Parent := TmpDataView;            // Родительский компонент
  end;
  // Создание TRaveRegion на котром будут расположены компоненты для работы с источником данных
  TmpRaveRegion := TRaveRegion.Create(TmpRaveReport.FirstPage);
  with TmpRaveRegion do
  begin
    Name := 'NewRaveRegion';
    Parent := TmpRaveReport.FirstPage;
    Left := SetPointInPercent(TmpRaveReport.FirstPage.PageWidth, 5);
    Top := SetPointInPercent(TmpRaveReport.FirstPage.PageHeight, 15);
    Width := SetPointInPercent(TmpRaveReport.FirstPage.PageWidth, 70);
    Height := SetPointInPercent(TmpRaveReport.FirstPage.PageHeight, 60);
  end;
  // Создание TRaveDataBand для размещения елементов оформления отчета на нем
  TmpRaveDataBand := TRaveDataBand.Create(TmpRaveRegion);
  with TmpRaveDataBand do
  begin
    Name := 'NewDataBand';
    Parent := TmpRaveRegion;
    Left := SetPointInPercent(TmpRaveRegion.Width, 5);
    Top := SetPointInPercent(TmpRaveRegion.Height, 5);
    Width := SetPointInPercent(TmpRaveRegion.Width, 90);
    Height := SetPointInPercent(TmpRaveRegion.Height, 5);
    DataView := TmpDataView;
  end;
  // TRaveDataText обеспечит отображение информации из источника данных
  TmpRaveDataText := TRaveDataText.Create(TmpRaveDataBand);
  with TmpRaveDataText do
  begin
    Name := 'NewDataText';
    Parent := TmpRaveDataBand;
    Left := SetPointInPercent(TmpRaveDataBand.Width, 1);
    Top := SetPointInPercent(TmpRaveDataBand.Height, 1);
    Width := SetPointInPercent(TmpRaveDataBand.Width, 50);
    DataView := TmpDataView;
    DataField := TmpDataField.FieldName;
  end;
  RvProjectRTR.ExecuteReport(NewRep);
end;

procedure TFormRTR.aViewReportUpdate(Sender: TObject);
begin
  if Sender is TAction then
    if RvProjectRTR.ProjMan.FindReport(NewRep, False) <> NIL then TAction(Sender).Enabled := True else TAction(Sender).Enabled := False;
end;

procedure TFormRTR.aConectDBUpdate(Sender: TObject);
begin
  if Sender is TAction then
    if RvProjectRTR.ProjMan.FindRaveComponent(NewDataView, RvProjectRTR.ProjMan) = NIL then TAction(Sender).Enabled := True else TAction(Sender).Enabled := False;
end;

end.

