unit FMXTee.Editor.Import;
{$I TeeDefs.inc}

interface

uses
  System.SysUtils, System.Types, System.UITypes, System.Rtti, System.Classes,
  System.Variants, FMX.Types, FMX.Controls, FMX.Forms, FMX.Dialogs,

  {$IFNDEF UPTOXE3}
  FMX.StdCtrls,
  {$ENDIF}

  {$IFDEF D21}
  FMX.ComboEdit,
  {$ENDIF}

  FMX.TabControl, FMX.Layouts, FMX.TreeView, FMX.ListBox, FMXTee.Chart, FMX.Edit,
  FMXTee.Engine, FMXTee.Procs;

type
  TImportEditor = class(TForm)
    TabControl1: TTabControl;
    PanelButtons: TLayout;
    TabOrigin: TTabItem;
    TabOptions: TTabItem;
    TabPreview: TTabItem;
    Layout1: TLayout;
    BImport: TButton;
    BPrevious: TSpeedButton;
    BNext: TSpeedButton;
    RGFile: TRadioButton;
    GroupBox1: TGroupBox;
    RGWeb: TRadioButton;
    RGComponent: TRadioButton;
    LFile: TLabel;
    CBFile: TComboEdit;
    LURL: TLabel;
    CBURL: TComboEdit;
    LComponent: TLabel;
    Tree: TTreeView;
    ChooseFile: TSpeedButton;
    OpenDialog1: TOpenDialog;
    PreviewChart: TChart;
    procedure FormResize(Sender: TObject);
    procedure BNextClick(Sender: TObject);
    procedure TabControl1Change(Sender: TObject);
    procedure BPreviousClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure BImportClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure CBFileChange(Sender: TObject);
    procedure CBURLChange(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure ChooseFileClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure RGFileChange(Sender: TObject);
    procedure TreeChange(Sender: TObject);
  private
    { Private declarations }

    ShouldSaveHistory,
    LoadedHistory : Boolean;

    procedure ImportTo(const AChart:TCustomChart);
    procedure LoadComponents;
    procedure LoadHistory;
    procedure SaveHistory;

    function SelectedComponent:TComponent;
    procedure ShowHideTabs;
    procedure TryAddHistory(const ACombo:TComboEdit);
  public
    { Public declarations }

    // When True, enable "Component" import source at runtime.
    // Default is False. Allow importing at design-time only.
    ComponentRuntime : Boolean;

    Chart : TCustomChart;
  end;

implementation

{$R *.fmx}

uses
  {$IFDEF MSWINDOWS}
  Winapi.Windows, Registry,
  {$ENDIF}
  Math,
  FMXTee.Editor.Stroke, FMXTee.Import, FMXTee.Canvas, FMXTee.Editor.Chart;

const
  Origin_File=0;
  Origin_URL=1;
  Origin_Component=2;
  Origin_Clipboard=3;

procedure TImportEditor.BImportClick(Sender: TObject);
begin
  ImportTo(Chart);

  if Owner is TChartEditForm then
  begin
    // Select just create SeriesGroup at Chart Editor
  end
  else
    ModalResult:=mrOk;
end;

procedure TImportEditor.BNextClick(Sender: TObject);
begin
  if TabControl1.ActiveTab=TabOptions then
  begin
    if CBFile.Visible then
       TryAddHistory(CBFile)
    else
    if CBURL.Visible then
       TryAddHistory(CBURL);
  end;

  TabControl1.TabIndex:=TabControl1.TabIndex+1;
  TabControl1Change(Self);
end;

procedure TImportEditor.BPreviousClick(Sender: TObject);
begin
  TabControl1.TabIndex:=TabControl1.TabIndex-1;
  TabControl1Change(Self);
end;

procedure TImportEditor.CBFileChange(Sender: TObject);
begin
  BNext.Enabled:=CBFile.Text<>'';
end;

procedure TImportEditor.CBURLChange(Sender: TObject);
begin
  BNext.Enabled:=CBURL.Text<>'';
end;

procedure TImportEditor.ChooseFileClick(Sender: TObject);
begin
  OpenDialog1.FileName:=CBFile.Text;

  if OpenDialog1.Execute then
  begin
    CBFile.Text:=OpenDialog1.FileName;

    TryAddHistory(CBFile);
  end;
end;

procedure TImportEditor.FormActivate(Sender: TObject);
//var tmp : Boolean;
begin
  (*
  tmp:=Clipboard.HasFormat(CF_TEXT) or Clipboard.HasFormat(CF_PICTURE);

  if tmp then
  begin
    if RGOrigin.Items.Count=3 then
       RGOrigin.Items.Add('Clipboard');
  end
  else
    if RGOrigin.Items.Count=4 then
       RGOrigin.Items.Delete(3);
  *)

  FormShow(Self);
end;

procedure TImportEditor.FormCreate(Sender: TObject);
begin
  TabControl1.TabIndex:=0;

  ShowHideTabs;
end;

procedure TImportEditor.FormDestroy(Sender: TObject);
begin
  if ShouldSaveHistory then
     SaveHistory;
end;

procedure TImportEditor.FormResize(Sender: TObject);
begin
  // Resize RadioGroup
  GroupBox1.Width:=Min(220,TabControl1.Width-32);

  CBFile.Width:=TabControl1.Width-81;
  ChooseFile.Position.X:=CBFile.Position.X+CBFile.Width+2;

  CBURL.Width:=CBFile.Width;

  Tree.Height:=TabControl1.Height-76;
  Tree.Width:=CBURL.Width;
end;

procedure TImportEditor.FormShow(Sender: TObject);
begin
  if Tag<>0 then
     Chart:=TCustomChart(Tag);

  if not Assigned(Chart) then
     if Assigned(TagObject) and (TagObject is TCustomChart) then
        Chart:=TCustomChart(TagObject);

  if (not Assigned(Chart)) or
     ((not (csDesigning in Chart.ComponentState)) and (not ComponentRuntime) ) then
        RGComponent.Visible:=False;
end;

procedure TImportEditor.RGFileChange(Sender: TObject);
begin
  PreviewChart.FreeAllSeries;
  PreviewChart.Title.Caption:='';

  BImport.Enabled:=False;
end;

procedure TImportEditor.TabControl1Change(Sender: TObject);

  function CanPreview:Boolean;
  begin
    result:=(CBFile.IsVisible and (Trim(CBFile.Text)<>'')) or
            (CBURL.IsVisible and (Trim(CBURL.Text)<>'')) or
            (Tree.Visible and (SelectedComponent<>nil))
            { or
            ((RGOrigin.ItemIndex=Origin_Clipboard) and Clipboard.HasFormat(CF_TEXT))
            };
  end;

begin
  BPrevious.Enabled:=TabControl1.TabIndex>0;
  BNext.Enabled:=TabControl1.TabIndex<TabControl1.TabCount-1;

  case TabControl1.TabIndex of
    0: FormActivate(Self);

    1: begin
         CBFile.Visible:=RGFile.IsChecked;
         LFile.Visible:=CBFile.Visible;
         ChooseFile.Visible:=CBFile.Visible;

         CBURL.Visible:=RGWeb.IsChecked;
         LURL.Visible:=CBURL.Visible;

         Tree.Visible:=RGComponent.IsChecked;
         LComponent.Visible:=Tree.Visible;

         if (not LoadedHistory) and
            ( CBFile.Visible or CBURL.Visible ) and
            ( (CBFile.Items.Count=0) or (CBURL.Items.Count=0) ) then
              LoadHistory;

         if Tree.Visible and (Tree.Count=0) then
            LoadComponents;

         if CBFile.Visible then
            BNext.Enabled:=Trim(CBFile.Text)<>'';

         if CBURL.Visible then
         begin
           LURL.Position.Y:=LFile.Position.Y;
           CBURL.Position.Y:=CBFile.Position.Y;

           BNext.Enabled:=Trim(CBURL.Text)<>'';
         end;

         if Tree.Visible then
         begin
           LComponent.Position.Y:=LFile.Position.Y;
           Tree.Position.Y:=CBFile.Position.Y;

           Tree.Height:=TabControl1.Height-76;

           BNext.Enabled:=SelectedComponent<>nil;
         end;
       end;

    2: if CanPreview then
       begin
         ImportTo(PreviewChart);
         BImport.Enabled:=Assigned(Chart);
       end;
  end;

  ShowHideTabs;
end;

procedure TImportEditor.TryAddHistory(const ACombo:TComboEdit);

  function ExistsItem(const AText:String):Boolean;
  var t : Integer;
  begin
    for t:=0 to ACombo.Items.Count-1 do
        if AText=UpperCase(Trim(ACombo.Items[t])) then
        begin
          result:=True;
          Exit;
        end;

    result:=False;
  end;

var S : String;
begin
  S:=UpperCase(Trim(ACombo.Text));

  if (S<>'') and (not ExistsItem(S)) then
  begin
    ACombo.Items.Insert(0, ACombo.Text);
    ShouldSaveHistory:=True;
  end;
end;

procedure TImportEditor.ImportTo(const AChart:TCustomChart);
var i : TDataImport;
begin
  i:=TDataImport.Create(Self);
  try
    i.Chart:=AChart;

    if RGFile.IsChecked then
       i.ImportFromFile(CBFile.Text)
    else
    if RGWeb.IsChecked then
       i.ImportFromURL(CBURL.Text)
    else
    if RGComponent.IsChecked then
       i.Import(SelectedComponent);

    (*
    else
      // Origin_Clipboard:

      {
      if Clipboard.HasFormat(CF_TEXT) then
         i.Import(Clipboard.AsText);
      }
    end;
    *)

  finally
    i.Free;
  end;
end;

procedure TImportEditor.LoadComponents;

  function ComponentTitle(const AComponent:TComponent):String;
  begin
    if AComponent is TCustomForm then
       result:=TCustomForm(AComponent).Caption
    else
       result:='';

    if result='' then
       result:=AComponent.Name;

    if result='' then
       result:=AComponent.ClassName;
  end;

  function NewNode(const AParent:TTreeViewItem; const AText:String; const ATag:TObject):TTreeViewItem;
  begin
    result:=TTreeViewItem.Create(Self);
    result.Text:=AText;
    result.TagObject:=ATag;

    if Assigned(AParent) then
       AParent.AddObject(result)
    else
       Tree.AddObject(result);
  end;

  procedure AddComponents(const ANode:TTreeViewItem);
  var t : Integer;
      AOwner : TComponent;
      tmp : TComponent;
  begin
    AOwner:=TComponent(ANode.TagObject);

    for t:=0 to AOwner.ComponentCount-1 do
    begin
      tmp:=AOwner.Components[t];

      if TDataImport.CanImport(tmp) then
         AddComponents(NewNode(ANode,ComponentTitle(tmp),tmp));
    end;
  end;

begin
  Tree.Clear;

  if Assigned(Chart) and Assigned(Chart.Owner) then
     AddComponents(NewNode(nil,ComponentTitle(Chart.Owner),Chart.Owner));

  if Tree.Count>0 then
     Tree.Items[0].IsExpanded:=True;
end;

const
  HistoryKey='Software\Steema Software\TeeChart Pro\Import';

procedure TImportEditor.LoadHistory;
{$IFDEF MSWINDOWS}
var R : TRegistry;

  procedure LoadItems(const Key:String; const AItems:TStrings);
  var t, n : Integer;
  begin
    AItems.Clear;

    if R.OpenKeyReadOnly(HistoryKey+'\'+Key) then
    try
      if R.ValueExists('Count') then
      begin
        n:=R.ReadInteger('Count');

        if n>0 then
        begin
          AItems.BeginUpdate;
          try
            for t:=0 to n-1 do
                AItems.Add(R.ReadString('Item'+IntToStr(t)));
          finally
            AItems.EndUpdate;
          end;
        end;
      end;

    finally
      R.CloseKey;
    end;
  end;

begin
  R:=TRegistry.Create(KEY_READ);
  try
    LoadItems('File_History',CBFile.Items);
    LoadItems('URL_History',CBURL.Items);

    LoadedHistory:=True;
  finally
    R.Free;
  end;
{$ELSE}
begin
{$ENDIF}
end;

procedure TImportEditor.SaveHistory;
{$IFDEF MSWINDOWS}
var R : TRegistry;

  procedure SaveItems(const Key:String; const AItems:TStrings);
  var t : Integer;
  begin
    if R.OpenKey(HistoryKey+'\'+Key,True) then
    begin
      for t:=0 to AItems.Count-1 do
          R.WriteString('Item'+IntToStr(t),AItems[t]);

      R.WriteInteger('Count',AItems.Count);
    end;
  end;

begin
  R:=TRegistry.Create;
  try
    SaveItems('File_History',CBFile.Items);
    SaveItems('URL_History',CBURL.Items);
  finally
    R.Free;
  end;
{$ELSE}
begin
{$ENDIF}
end;

function TImportEditor.SelectedComponent: TComponent;
begin
  if Assigned(Tree.Selected) and Assigned(Tree.Selected.TagObject) then
     result:=TComponent(Tree.Selected.TagObject)
  else
     result:=nil;
end;

procedure TImportEditor.ShowHideTabs;
var Old,
    t : Integer;
begin
  Old:=TabControl1.TabIndex;

  for t:=0 to TabControl1.TabCount-1 do
      TabControl1.Tabs[t].Visible:=t=Old;

  TabControl1.TabIndex:=Old;
end;

procedure TImportEditor.TreeChange(Sender: TObject);
begin
  BImport.Enabled:=Tree.Visible and (SelectedComponent<>nil);
  BNext.Enabled:=BImport.Enabled;
end;

initialization
  TChartEditForm.ImportEditor:=TImportEditor;
finalization
  TChartEditForm.ImportEditor:=nil;
end.
