{*************************************************************************}
{                                                                         }
{ written by TMS Software                                                 }
{           copyright © 2013 - 2014                                       }
{           Email : info@tmssoftware.com                                  }
{           Web : http://www.tmssoftware.com                              }
{                                                                         }
{ The source code is given as is. The author is not responsible           }
{ for any possible damage done due to the use of this code.               }
{ The component can be freely used in any application. The complete       }
{ source code remains property of the author and may not be distributed,  }
{ published, given or sold in any form as such. No parts of the source    }
{ code can be included in any other component or application without      }
{ written authorization of the author.                                    }
{*************************************************************************}

unit FMX.TMSMemoDialogs;

interface

{$I TMSDEFS.INC}

uses
  Classes, SysUtils, FMX.Dialogs, FMX.TMSMemo, FMX.TMSFindDialog, FMX.TMSReplaceDialog;

type
  TTMSFMXMemoFindDialog = class(TComponent)
  private
    FMemo: TTMSFMXMemo;
    FUILanguage: TFindUILanguage;
    FOptions: TTMSFMXFindDialogOptions;
    FVisibleOptions: TTMSFMXFindDialogVisibleOptions;
    FFindText: string;
    FFindList: TStringList;
    FAutoHighlight: boolean;
    FNotFoundMessage: string;
    FOnClose: TNotifyEvent;
    FOnFind: TNotifyEvent;
    FOnFindEditChange: TFindEditChangeEvent;
    FOnFindPrevious: TNotifyEvent;
    procedure SetUILanguage(const Value: TFindUILanguage);
    procedure SetFindList(const Value: TStringList);
  protected
    procedure DoFindEditChange(Sender: TObject; var AText: string);
    procedure DoFind(Sender: TObject);
    procedure DoClose(Sender: TObject);
    procedure DoFindPrevious(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function Execute: integer;
  published
    property AutoHighlight: boolean read FAutoHighlight write FAutoHighlight default false;
    property FindText: string read FFindText write FFindText;
    property FindList: TStringList read FFindList write SetFindList;
    property Memo: TTMSFMXMemo read FMemo write FMemo;
    property NotFoundMessage: string read FNotFoundMessage write FNotFoundMessage;
    property Options: TTMSFMXFindDialogOptions read FOptions write FOptions default DefaultFindOptions;
    property UILanguage: TFindUILanguage read FUILanguage write SetUILanguage;
    property VisibleOptions: TTMSFMXFindDialogVisibleOptions read FVisibleOptions write FVisibleOptions default DefaultVisibleFindOptions;
    property OnFindEditChange: TFindEditChangeEvent read FOnFindEditChange write FOnFindEditChange;
    property OnFind: TNotifyEvent read FOnFind write FOnFind;
    property OnClose: TNotifyEvent read FOnClose write FOnClose;
    property OnFindPrevious: TNotifyEvent read FOnFindPrevious write FOnFindPrevious;
  end;

  TTMSFMXMemoFindAndReplaceDialog = class(TComponent)
  private
    FMemo: TTMSFMXMemo;
    FUILanguage: TReplaceUILanguage;
    FOptions: TTMSFMXReplaceDialogOptions;
    FVisibleOptions: TTMSFMXReplaceDialogVisibleOptions;
    FFindText: string;
    FFindList: TStringList;
    FReplaceText: string;
    FReplaceList: TStringList;
    FAutoHighlight: boolean;
    FNotFoundMessage: string;
    FOnFind: TNotifyEvent;
    FOnReplace: TNotifyEvent;
    FOnFindEditChange: TEditChangeEvent;
    FOnReplaceEditChange: TEditChangeEvent;
    FOnReplaceAll: TNotifyEvent;
    FOnClose: TNotifyEvent;
    procedure SetUILanguage(const Value: TReplaceUILanguage);
    procedure SetFindList(const Value: TStringList);
    procedure SetReplaceList(const Value: TStringList);
  protected
    procedure DoClose(Sender: TObject);
    procedure DoReplaceEditChange(Sender: TObject; var AText: String);
    procedure DoFindEditChange(Sender: TObject; var AText: string);
    procedure DoFind(Sender: TObject);
    procedure DoReplace(Sender: TObject);
    procedure DoReplaceAll(Sender: TObject);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function Execute: integer;
  published
    property AutoHighlight: boolean read FAutoHighlight write FAutoHighlight default false;
    property FindText: string read FFindText write FFindText;
    property FindList: TStringList read FFindList write SetFindList;
    property Memo: TTMSFMXMemo read FMemo write FMemo;
    property NotFoundMessage: string read FNotFoundMessage write FNotFoundMessage;
    property Options: TTMSFMXReplaceDialogOptions read FOptions write FOptions default DefaultReplaceOptions;
    property ReplaceList: TStringList read FReplaceList write SetReplaceList;
    property ReplaceText: string read FReplaceText write FReplaceText;
    property UILanguage: TReplaceUILanguage read FUILanguage write SetUILanguage;
    property VisibleOptions: TTMSFMXReplaceDialogVisibleOptions read FVisibleOptions write FVisibleOptions default DefaultVisibleReplaceOptions;

    property OnReplace: TNotifyEvent read FOnReplace write FOnReplace;
    property OnClose: TNotifyEvent read FOnClose write FOnClose;
    property OnReplaceAll: TNotifyEvent read FOnReplaceAll write FOnReplaceAll;
    property OnFind: TNotifyEvent read FOnFind write FOnFind;
    property OnFindEditChange: TEditChangeEvent read FOnFindEditChange write FOnFindEditChange;
    property OnReplaceEditChange: TEditChangeEvent read FOnReplaceEditChange write FOnReplaceEditChange;
  end;


implementation

const
  NOT_FOUND_MESSAGE = 'Finished searching the document. The search item was not found.';

{ TTMSFMXMemoFindDialog }

constructor TTMSFMXMemoFindDialog.Create(AOwner: TComponent);
begin
  inherited;
  FUILanguage := TFindUILanguage.Create(Self);

  if(csDesigning in AOwner.ComponentState) and not
    ((csReading in AOwner.ComponentState) or (csLoading in AOwner.ComponentState)) then
  begin
    FUILanguage.Init;
    FNotFoundMessage := NOT_FOUND_MESSAGE;
  end;

  FFindList := TStringList.Create;

  FOptions := DefaultFindOptions;
  FVisibleOptions := DefaultVisibleFindOptions;
end;

destructor TTMSFMXMemoFindDialog.Destroy;
begin
  FFindList.Free;
  FUILanguage.Free;
  inherited;
end;

procedure TTMSFMXMemoFindDialog.DoClose(Sender: TObject);
begin
  if Assigned(OnClose) then
    OnClose(Self);
end;

procedure TTMSFMXMemoFindDialog.DoFind(Sender: TObject);
var
  fd: TTMSFMXFindDialog;
  opt: TTMSFMXFindDialogOptions;
  res: integer;
begin
  fd := (Sender as TTMSFMXFindDialog);
  opt := fd.Options;

  res := FMemo.FindText(fd.FindText,opt);
  if (res = -1) and (FNotFoundMessage <> '') then
    ShowMessage(FNotFoundMessage);

  if Assigned(OnFind) then
    OnFind(Self);
end;

procedure TTMSFMXMemoFindDialog.DoFindEditChange(Sender: TObject;
  var AText: string);
begin
  if Assigned(OnFindEditChange) then
    OnFindEditChange(Self, AText);

  if AutoHighlight then
    FMemo.HighlightText := AText;
end;

procedure TTMSFMXMemoFindDialog.DoFindPrevious(Sender: TObject);
var
  fd: TTMSFMXFindDialog;
  opt: TTMSFMXFindDialogOptions;
begin
  fd := (Sender as TTMSFMXFindDialog);

  opt := fd.Options;
  opt := opt - [TTMSFMXFindDialogOption.fdoDown];

  FMemo.FindText(fd.FindText,opt);

  if Assigned(OnFindPrevious) then
    OnFindPrevious(Self);
end;

function TTMSFMXMemoFindDialog.Execute: integer;
var
  fd: TTMSFMXFindDialog;
begin
  Result := -1;
  if not Assigned(FMemo) then
    raise Exception.Create('No memo assigned');

  fd := TTMSFMXFindDialog.Create(Self);
  try
    fd.OnClose := DoClose;
    fd.OnFind := DoFind;
    fd.OnFindPrevious := DoFindPrevious;
    fd.OnFindEditChange := DoFindEditChange;
    fd.Options := FOptions;
    fd.VisibleOptions := FVisibleOptions;
    fd.FindText := FFindText;
    fd.FindList.Assign(FFindList);

    fd.UILanguage.Init;
    fd.Execute;

    if AutoHighlight then
      FMemo.HighlightText := '';

    FFindText := fd.FindText;
    FOptions := fd.Options;
    FFindList.Assign(fd.FindList);
  finally
    fd.Free;
  end;
end;

procedure TTMSFMXMemoFindDialog.SetFindList(const Value: TStringList);
begin
  FFindList.Assign(Value);
end;

procedure TTMSFMXMemoFindDialog.SetUILanguage(const Value: TFindUILanguage);
begin
  FUILanguage.Assign(Value);
end;

{ TTMSFMXMemoFindAndReplaceDialog }

constructor TTMSFMXMemoFindAndReplaceDialog.Create(AOwner: TComponent);
begin
  inherited;
  FUILanguage := TReplaceUILanguage.Create(Self);

  if(csDesigning in AOwner.ComponentState) and not
    ((csReading in AOwner.ComponentState) or (csLoading in AOwner.ComponentState)) then
  begin
    FUILanguage.Init;
    FNotFoundMessage := NOT_FOUND_MESSAGE;
  end;

  FFindList := TStringList.Create;
  FReplaceList := TStringList.Create;

  FOptions := DefaultReplaceOptions;
  FVisibleOptions := DefaultVisibleReplaceOptions;
end;

destructor TTMSFMXMemoFindAndReplaceDialog.Destroy;
begin
  FReplaceList.Free;
  FFindList.Free;
  FUILanguage.Free;
  inherited;
end;

procedure TTMSFMXMemoFindAndReplaceDialog.DoClose(Sender: TObject);
begin
  if Assigned(OnClose) then
    OnClose(Self);
end;

procedure TTMSFMXMemoFindAndReplaceDialog.DoFind(Sender: TObject);
var
  fd: TTMSFMXReplaceDialog;
  opt: TTMSFMXFindDialogOptions;
  res: integer;
begin
  fd := (Sender as TTMSFMXReplaceDialog);

  opt := [];

  if (TTMSFMXReplaceDialogOption.fdoDown in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoDown];

  if (TTMSFMXReplaceDialogOption.fdoCaseSensitive in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoCaseSensitive];

  if (TTMSFMXReplaceDialogOption.fdoSelection in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoSelection];

  if (TTMSFMXReplaceDialogOption.fdoExpression in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoExpression];

  if (TTMSFMXReplaceDialogOption.fdoWholeWordOnly in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoWholeWordOnly];

  if (TTMSFMXReplaceDialogOption.fdoWrapAtEndOfFile in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoWrapAtEndOfFile];

  res := FMemo.FindText(fd.FindText,opt);
  if (res = -1) and (FNotFoundMessage <> '') then
    ShowMessage(FNotFoundMessage);

  if Assigned(OnFind) then
    OnFind(Self);
end;

procedure TTMSFMXMemoFindAndReplaceDialog.DoFindEditChange(Sender: TObject;
  var AText: string);
begin
  if Assigned(OnFindEditChange) then
    OnFindEditChange(Self, AText);

  if AutoHighlight then
    FMemo.HighlightText := AText;
end;

procedure TTMSFMXMemoFindAndReplaceDialog.DoReplaceAll(Sender: TObject);
var
  fd: TTMSFMXReplaceDialog;
  opt: TTMSFMXFindDialogOptions;
begin
  fd := (Sender as TTMSFMXReplaceDialog);

  opt := [];
  opt := opt + [TTMSFMXFindDialogOption.fdoDown];

  if (TTMSFMXReplaceDialogOption.fdoCaseSensitive in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoCaseSensitive];

  if (TTMSFMXReplaceDialogOption.fdoSelection in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoSelection];

  if (TTMSFMXReplaceDialogOption.fdoExpression in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoExpression];

  if (TTMSFMXReplaceDialogOption.fdoWholeWordOnly in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoWholeWordOnly];

  if (TTMSFMXReplaceDialogOption.fdoWrapAtEndOfFile in fd.Options) then
    opt := opt + [TTMSFMXFindDialogOption.fdoWrapAtEndOfFile];

  FMemo.FindAndReplace(fd.FindText,fd.ReplaceText,opt);

  if Assigned(OnReplaceAll) then
    OnReplaceAll(Self);
end;

procedure TTMSFMXMemoFindAndReplaceDialog.DoReplaceEditChange(Sender: TObject;
  var AText: String);
begin
  if Assigned(OnReplaceEditChange) then
    OnReplaceEditChange(Self, AText);
end;

procedure TTMSFMXMemoFindAndReplaceDialog.DoReplace(Sender: TObject);
var
  fd: TTMSFMXReplaceDialog;
begin
  fd := (Sender as TTMSFMXReplaceDialog);

  if FMemo.Selection <> '' then
    FMemo.Selection := fd.ReplaceText;

  if Assigned(OnReplace) then
    OnReplace(Self);
end;

function TTMSFMXMemoFindAndReplaceDialog.Execute: integer;
var
  fd: TTMSFMXReplaceDialog;
begin
  Result := -1;
  if not Assigned(FMemo) then
    raise Exception.Create('No memo assigned');

  fd := TTMSFMXReplaceDialog.Create(Self);
  try
    fd.OnFind := DoFind;
    fd.OnFindEditChange := DoFindEditChange;
    fd.OnReplace := DoReplace;
    fd.OnReplaceAll := DoReplaceAll;
    fd.Options := FOptions;
    fd.VisibleOptions := FVisibleOptions;
    fd.FindText := FFindText;
    fd.ReplaceText := FReplaceText;
    fd.FindList.Assign(FFindList);
    fd.ReplaceList.Assign(FReplaceList);

    fd.UILanguage.Init;
    fd.Execute;

    FFindText := fd.FindText;
    FFindList.Assign(fd.FindList);
    FReplaceText := fd.ReplaceText;
    FReplaceList.Assign(fd.ReplaceList);

  finally
    fd.Free;
  end;
end;

procedure TTMSFMXMemoFindAndReplaceDialog.SetFindList(const Value: TStringList);
begin
  FFindList.Assign(Value);
end;

procedure TTMSFMXMemoFindAndReplaceDialog.SetReplaceList(
  const Value: TStringList);
begin
  FReplaceList.Assign(Value);
end;

procedure TTMSFMXMemoFindAndReplaceDialog.SetUILanguage(
  const Value: TReplaceUILanguage);
begin
  FUILanguage.Assign(Value);
end;

end.
