
{******************************************}
{                                          }
{             FastReport v3.0              }
{          Data Tree tool window           }
{                                          }
{         Copyright (c) 1998-2006          }
{         by Alexander Tzyganenko,         }
{            Fast Reports Inc.             }
{                                          }
{******************************************}

unit frxDataTree;

interface

{$I frx.inc}

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, frxClass, fs_xml, ComCtrls
{$IFDEF Delphi6}
, Variants
{$ENDIF};
  

type
  TfrxDataTreeForm = class(TForm)
    Tabs: TPageControl;
    DataTS: TTabSheet;
    VariablesTS: TTabSheet;
    DataTree: TTreeView;
    VariablesTree: TTreeView;
    FunctionsTS: TTabSheet;
    FunctionsTree: TTreeView;
    HintPanel: TPanel;
    Splitter1: TSplitter;
    FunctionDescL: TLabel;
    FunctionNameL: TLabel;
    CBPanel: TPanel;
    InsFieldCB: TCheckBox;
    InsCaptionCB: TCheckBox;
    ClassesTS: TTabSheet;
    ClassesTree: TTreeView;
    procedure FormResize(Sender: TObject);
    procedure DataTreeCustomDrawItem(Sender: TCustomTreeView;
      Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
    procedure FunctionsTreeChange(Sender: TObject; Node: TTreeNode);
    procedure DataTreeDblClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ClassesTreeExpanding(Sender: TObject; Node: TTreeNode;
      var AllowExpansion: Boolean);
    procedure FunctionsTSShow(Sender: TObject);
  private
    { Private declarations }
    FXML: TfsXMLDocument;
    FImages: TImageList;
    FReport: TfrxReport;
    FUpdating: Boolean;
    FFirstTime: Boolean;
    procedure FillClassesTree;
    procedure FillDataTree;
    procedure FillFunctionsTree;
    procedure FillVariablesTree;
    function GetCollapsedNodes: String;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure SetColor(Color: TColor);
    procedure UpdateItems;
    function GetFieldName: String;
    function IsDataField: Boolean;
    property Report: TfrxReport read FReport write FReport;
  end;


implementation

{$R *.DFM}

uses fs_iinterpreter, fs_itools, frxRes;

var
  CollapsedNodes: String;

procedure SetImageIndex(Node: TTreeNode; Index: Integer);
begin
  Node.ImageIndex := Index;
  Node.StateIndex := Index;
  Node.SelectedIndex := Index;
end;


{ TfrxDataTreeForm }

constructor TfrxDataTreeForm.Create(AOwner: TComponent);
begin
  inherited;
  FImages := frxResources.MainButtonImages;
  DataTree.Images := FImages;
  VariablesTree.Images := FImages;
  FunctionsTree.Images := FImages;
  ClassesTree.Images := FImages;
  FXML := TfsXMLDocument.Create;
  FFirstTime := True;
end;

destructor TfrxDataTreeForm.Destroy;
begin
  if Owner is TfrxCustomDesigner then
    CollapsedNodes := GetCollapsedNodes;
  FUpdating := True;
  FXML.Free;
  inherited;
end;

procedure TfrxDataTreeForm.FillDataTree;
var
  ds: TfrxDataSet;
  DatasetsList, FieldsList: TStrings;
  i, j: Integer;
  Root, Node1, Node2: TTreeNode;
  s, Collapsed: String;
begin
  DatasetsList := TStringList.Create;
  FieldsList := TStringList.Create;
  FReport.GetDataSetList(DatasetsList);

  try
    if FFirstTime then
      Collapsed := CollapsedNodes
    else
      Collapsed := GetCollapsedNodes;

    DataTree.Items.BeginUpdate;
    DataTree.Items.Clear;
    if DatasetsList.Count = 0 then
      s := frxResources.Get('dtNoData') else
      s := frxResources.Get('dtData');
    Root := DataTree.Items.AddChild(nil, s);
    SetImageIndex(Root, 53);

    for i := 0 to DatasetsList.Count - 1 do
    begin
      ds := TfrxDataSet(DatasetsList.Objects[i]);
      if ds = nil then continue;
      ds.GetFieldList(FieldsList);

      Node1 := DataTree.Items.AddChild(Root, FReport.GetAlias(ds));
      Node1.Data := ds;
      SetImageIndex(Node1, 53);

      for j := 0 to FieldsList.Count - 1 do
      begin
        Node2 := DataTree.Items.AddChild(Node1, FieldsList[j]);
        Node2.Data := ds;
        SetImageIndex(Node2, 54);
      end;
    end;

    DataTree.Items[0].Expanded := True;
    for i := 0 to DataTree.Items[0].Count - 1 do
    begin
      s := DataTree.Items[0][i].Text;
      if Pos(s + ',', Collapsed) = 0 then
        DataTree.Items[0][i].Expanded := True;
    end;

  finally
    DataTree.Items.EndUpdate;
    DatasetsList.Free;
    FieldsList.Free;
  end;
end;

procedure TfrxDataTreeForm.FillVariablesTree;
var
  CategoriesList, VariablesList: TStrings;
  i: Integer;
  Root, Node: TTreeNode;

  procedure AddVariables(Node: TTreeNode);
  var
    i: Integer;
    Node1: TTreeNode;
  begin
    for i := 0 to VariablesList.Count - 1 do
    begin
      Node1 := VariablesTree.Items.AddChild(Node, VariablesList[i]);
      SetImageIndex(Node1, 80);
    end;
  end;

{  procedure AddScriptVariables;
  var
    i: Integer;
    x: TfsXMLDocument;
    xi: TfsXMLItem;
    Node: TTreeNode;
    s: String;
  begin
    x := TfsXMLDocument.Create;
    GenerateXMLContents(FReport.Script, x.Root);

    xi := x.Root.FindItem('Variables');
    for i := 0 to xi.Count - 1 do
    begin
      s := xi[i].Prop['text'];
      s := Copy(s, 1, Pos(':', s) - 1);
      Node := VariablesTree.Items.AddChild(Root, s);
      Node.Data := Pointer(1);
      SetImageIndex(Node, 80);
    end;

    x.Free;
  end;}

  procedure AddSystemVariables;
  var
    SysNode: TTreeNode;

    procedure AddNode(const s: String);
    var
      Node: TTreeNode;
    begin
      Node := VariablesTree.Items.AddChild(SysNode, s);
      SetImageIndex(Node, 80);
    end;

  begin
    SysNode := VariablesTree.Items.AddChild(Root, frxResources.Get('dtSysVar'));
    SetImageIndex(SysNode, 66);

    AddNode('Date');
    AddNode('Time');
    AddNode('Page');
    AddNode('Page#');
    AddNode('TotalPages');
    AddNode('TotalPages#');
    AddNode('Line');
    AddNode('Line#');
  end;

begin
  CategoriesList := TStringList.Create;
  VariablesList := TStringList.Create;
  FReport.Variables.GetCategoriesList(CategoriesList);

  VariablesTree.Items.BeginUpdate;
  VariablesTree.Items.Clear;
  Root := VariablesTree.Items.AddChild(nil, frxResources.Get('dtVar'));
  SetImageIndex(Root, 66);

  for i := 0 to CategoriesList.Count - 1 do
  begin
    FReport.Variables.GetVariablesList(CategoriesList[i], VariablesList);
    Node := VariablesTree.Items.AddChild(Root, CategoriesList[i]);
    SetImageIndex(Node, 66);
    AddVariables(Node);
  end;

  if CategoriesList.Count = 0 then
  begin
    FReport.Variables.GetVariablesList('', VariablesList);
    AddVariables(Root);
  end;

//  AddScriptVariables;
  AddSystemVariables;

  VariablesTree.FullExpand;
  VariablesTree.TopItem := Root;
  VariablesTree.Items.EndUpdate;
  CategoriesList.Free;
  VariablesList.Free;
end;

procedure TfrxDataTreeForm.FillFunctionsTree;

  procedure AddFunctions(xi: TfsXMLItem; Root: TTreeNode);
  var
    i: Integer;
    Node: TTreeNode;
    s: String;
  begin
    s := xi.Prop['text'];
    if xi.Count = 0 then
      s := Copy(s, Pos(' ', s) + 1, 255) else  { function }
      s := frxResources.Get(s);                { category }

    if CompareText(s, 'hidden') = 0 then Exit;
    Node := FunctionsTree.Items.AddChild(Root, s);
    if xi.Count = 0 then
      Node.Data := xi;
    if Root = nil then
      Node.Text := frxResources.Get('dtFunc');
    if xi.Count = 0 then
      SetImageIndex(Node, 80) else
      SetImageIndex(Node, 66);

    for i := 0 to xi.Count - 1 do
      AddFunctions(xi[i], Node);
  end;

begin
  FUpdating := True;

  FunctionsTree.Items.BeginUpdate;
  FunctionsTree.Items.Clear;
  AddFunctions(FXML.Root.FindItem('Functions'), nil);

  FunctionsTree.FullExpand;
  FunctionsTree.TopItem := FunctionsTree.Items[0];
  FunctionsTree.Items.EndUpdate;
  FUpdating := False;
end;

procedure TfrxDataTreeForm.FillClassesTree;

  procedure AddClasses(xi: TfsXMLItem; Root: TTreeNode);
  var
    i: Integer;
    Node: TTreeNode;
    s: String;
  begin
    s := xi.Prop['text'];

    Node := ClassesTree.Items.AddChild(Root, s);
    Node.Data := xi;
    if Root = nil then
      Node.Text := frxResources.Get('2106');
    SetImageIndex(Node, 66);

    if Root = nil then
    begin
      for i := 0 to xi.Count - 1 do
        AddClasses(xi[i], Node);
    end
    else
      ClassesTree.Items.AddChild(Node, 'more...');  // do not localize
  end;

begin
  FUpdating := True;

  ClassesTree.Items.BeginUpdate;
  ClassesTree.Items.Clear;
  AddClasses(FXML.Root.FindItem('Classes'), nil);

  ClassesTree.TopItem := ClassesTree.Items[0];
  ClassesTree.TopItem.Expand(False);
  ClassesTree.Items.EndUpdate;
  FUpdating := False;
end;

function TfrxDataTreeForm.GetCollapsedNodes: String;
var
  i: Integer;
  s: String;
begin
  Result := '';
  if DataTree.Items.Count > 0 then
    for i := 0 to DataTree.Items[0].Count - 1 do
    begin
      s := DataTree.Items[0][i].Text;
      if not DataTree.Items[0][i].Expanded then
        Result := Result + s + ',';
    end;
end;

function TfrxDataTreeForm.GetFieldName: String;
var
  i, n: Integer;
  s: String;
  Node: TTreeNode;
begin
  Result := '';
  if Tabs.ActivePage = DataTS then
  begin
    Node := DataTree.Selected;
    if (Node <> nil) and (Node.Count = 0) and (Node.Data <> nil) then
      Result := '<' + FReport.GetAlias(TfrxDataSet(Node.Data)) +
        '."' + Node.Text + '"' + '>';
  end
  else if Tabs.ActivePage = VariablesTS then
  begin
    Node := VariablesTree.Selected;
    if (Node <> nil) and (Node.Count = 0) then
      if Node.Data <> nil then
        Result := Node.Text else
        Result := '<' + Node.Text + '>';
  end
  else if Tabs.ActivePage = FunctionsTS then
  begin
    if (FunctionsTree.Selected <> nil) and (FunctionsTree.Selected.Count = 0) then
    begin
      s := FunctionsTree.Selected.Text;
      if Pos('(', s) <> 0 then
        n := 1 else
        n := 0;
      for i := 1 to Length(s) do
        if s[i] in [',', ';'] then
          Inc(n);

      if n = 0 then
        s := Copy(s, 1, Pos(':', s) - 1)
      else
      begin
        s := Copy(s, 1, Pos('(', s));
        for i := 1 to n - 1 do
          s := s + ',';
        s := s + ')';
      end;
      Result := s;
    end;
  end;
end;

function TfrxDataTreeForm.IsDataField: Boolean;
begin
  Result := Tabs.ActivePage = DataTS;
end;

procedure TfrxDataTreeForm.UpdateItems;
begin
  FillDataTree;
  FillVariablesTree;
  FFirstTime := False;
end;

procedure TfrxDataTreeForm.SetColor(Color: TColor);
begin
  DataTree.Color := Color;
  VariablesTree.Color := Color;
  FunctionsTree.Color := Color;
  ClassesTree.Color := Color;
end;

procedure TfrxDataTreeForm.FormResize(Sender: TObject);
begin
  AutoScroll := False;
  Tabs.SetBounds(-4, 0, ClientWidth + 8, ClientHeight + 4);
end;

procedure TfrxDataTreeForm.DataTreeCustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  if Node.Count <> 0 then
    Sender.Canvas.Font.Style := [fsBold];
end;

procedure TfrxDataTreeForm.FunctionsTreeChange(Sender: TObject;
  Node: TTreeNode);
var
  xi: TfsXMLItem;
begin
  if FUpdating then Exit;
  Node := FunctionsTree.Selected;
  if (Node = nil) or (Node.Data = nil) then
  begin
    FunctionNameL.Caption := '';
    FunctionDescL.Caption := '';
    Exit;
  end
  else
  begin
    xi := Node.Data;
    FunctionNameL.Caption := xi.Prop['text'];
    FunctionDescL.Caption := frxResources.Get(xi.Prop['description']);
    FunctionNameL.AutoSize := True;
  end;
end;

procedure TfrxDataTreeForm.DataTreeDblClick(Sender: TObject);
begin
  if Assigned(OnDblClick) then
    OnDblClick(Sender);
end;

procedure TfrxDataTreeForm.FormCreate(Sender: TObject);
begin
  Caption := frxGet(2100);
  DataTS.Caption := frxGet(2101);
  VariablesTS.Caption := frxGet(2102);
  FunctionsTS.Caption := frxGet(2103);
  ClassesTS.Caption := frxGet(2106);
  InsFieldCB.Caption := frxGet(2104);
  InsCaptionCB.Caption := frxGet(2105);
end;

procedure TfrxDataTreeForm.ClassesTreeExpanding(Sender: TObject;
  Node: TTreeNode; var AllowExpansion: Boolean);
var
  i: Integer;
  xi: TfsXMLItem;
  s: String;
  n: TTreeNode;
begin
  if (Node.Level = 1) and (Node.Data <> nil) then
  begin
    FUpdating := True;
    ClassesTree.Items.BeginUpdate;

    Node.DeleteChildren;
    xi := TfsXMLItem(Node.Data);
    Node.Data := nil;

    for i := 0 to xi.Count - 1 do
    begin
      s := xi[i].Prop['text'];
      n := ClassesTree.Items.AddChild(Node, s);
      SetImageIndex(n, 75);
    end;

    ClassesTree.Items.EndUpdate;
  end;
end;

procedure TfrxDataTreeForm.FunctionsTSShow(Sender: TObject);
begin
  if FXML.Root.Count = 0 then
  begin
    FReport.Script.AddRTTI;
    GenerateXMLContents(FReport.Script, FXML.Root);
  end;

  if (Sender = FunctionsTS) and (FunctionsTree.Items.Count = 0) then
    FillFunctionsTree;
  if (Sender = ClassesTS) and (ClassesTree.Items.Count = 0) then
    FillClassesTree;
end;

end.


//<censored>