/// SynFile Edit window
unit FileEdit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, ExtCtrls, ExtDlgs,
{$ifdef USETMSPACK}
  TaskDialog,
{$endif}
  SynCommons, SynCrypto, SynGdiPlus, SynTaskDialog,
  mORMot, mORMotUILogin, mORMotUI, mORMoti18n,
  FileTables;

type
  /// SynFile Edit window
  // - we don't use the standard Window generation (from mORMotUIEdit),
  // but a custom window, created as RAD
  TEditForm = class(TVistaForm)
    Name: TLabeledEdit;
    KeyWords: TLabeledEdit;
    Memo: TMemo;
    procedure FormShow(Sender: TObject);
    procedure BtnOkClick(Sender: TObject);
    procedure BtnPictureClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
  private
    fRec: TSQLFile;
    fReadOnly: boolean;
    BtnOk: TSynButton;
    BtnCancel: TSynButton;
    BtnPicture: TSynButton;
  public
    /// set the associated record to be edited
    function SetRec(const Value: TSQLFile): boolean;
	/// used to load a picture file into a BLOB content 
	// after 80% JPEG compression
    function LoadPicture(const FileName: TFileName; var Picture: RawByteString): boolean;
	/// read-only access to the edited record
    property Rec: TSQLFile read fRec;
	/// should be set to TRUE to disable any content editing
    property ReadOnly: boolean read fReadOnly write fReadOnly;
  end;

var
  /// SynFile Edit window instance
  EditForm: TEditForm;

/// will display a modal form asking for a password, then encrypt
// or uncrypt some BLOB content
// - returns TRUE if the password was correct and the data processed
// - returns FALSE on error (canceled or wrong password)
function Cypher(const Title: string; var Content: TSQLRawBlob; Encrypt: boolean): boolean;


implementation

{$R *.dfm}

{ TEditForm }

function TEditForm.SetRec(const Value: TSQLFile): boolean;
begin
  result := false;
  fRec := Value;
  Name.Text := U2S(Value.fName);
  KeyWords.Text := U2S(Value.fKeyWords);
  if Value.InheritsFrom(TSQLData) and not Value.InheritsFrom(TSQLSafeMemo) then begin
    Memo.Hide;
    ClientHeight := 165;
  end else begin
    Memo.Show;
    ClientHeight := 500;
    if Value.InheritsFrom(TSQLMemo) then
      Memo.Text := U2S(TSQLMemo(Value).Content) else
    if Value.InheritsFrom(TSQLSafeMemo) then
      with TSQLSafeMemo(Value) do
        if not Cypher(Rec.CaptionName,fData,false) then
          exit else
          Memo.Text := U2S(Data) else
      Memo.Hide;
  end;
  Name.ReadOnly := ReadOnly;
  KeyWords.ReadOnly := ReadOnly;
  if Memo.Visible then
    Memo.ReadOnly := ReadOnly;
  BtnCancel.Visible := not ReadOnly;
  result := true;
end;


procedure TEditForm.FormCreate(Sender: TObject);
resourcestring
  BtnPictureHint = 'Change the Picture associated with this record';
begin
  BtnOK := TSynButton.CreateKind(self,cbOK,337,437,100,41);
  BtnOK.ModalResult := mrNone;
  BtnOK.OnClick := BtnOKClick;
  BtnOK.Anchors := [akRight, akBottom];
  BtnCancel := TSynButton.CreateKind(self,cbCancel,457,437,100,41);
  BtnCancel.Anchors := [akRight, akBottom];
  BtnPicture := TSynButton.Create(self);
  BtnPicture.Parent := self;
  BtnPicture.SetBounds(392,21,105,25);
  BtnPicture.Hint := BtnPictureHint;
  BtnPicture.OnClick := BtnPictureClick;
end;

procedure TEditForm.FormShow(Sender: TObject);
begin
  Name.EditLabel.Caption := _('Name');
  KeyWords.EditLabel.Caption := _('KeyWords');
  BtnPicture.Caption := _('Picture');
  SetStyle(self);
end;

procedure TEditForm.BtnOkClick(Sender: TObject);
begin
  if ReadOnly then
    ModalResult := mrCancel else begin
    Rec.fModified := TimeLogNow;
    Rec.fName := trim(S2U(Name.Text));
    if Rec.fName='' then begin
      Name.SetFocus;
      ShowMessage(_('Name'),true);
      exit;
    end;
    Rec.fKeyWords := trim(S2U(KeyWords.Text));
    if Rec.InheritsFrom(TSQLMemo) then
      TSQLMemo(Rec).Content := S2U(Memo.Text) else
    if Rec.ClassType=TSQLSafeMemo then
    with TSQLSafeMemo(Rec) do begin
      Data := S2U(Memo.Text);
      if not Cypher(Rec.CaptionName,fData,true) then
        exit;
    end;
    ModalResult := mrOk;
  end;
end;

function Cypher(const Title: string; var Content: TSQLRawBlob; Encrypt: boolean): boolean;
resourcestring
  sEnterPassword = 'Enter password for this record:';
var AES: TAESFull;
    SHA: TSHA256Digest;
    PassWord: string;
    Len: integer;
begin
  result := Content='';
  if result then
    exit;
  if not TLoginForm.PassWord(Title,sEnterPassword,PassWord) then
    exit;
  SHA256Weak(S2U(PassWord), SHA);
  try
    Len := AES.EncodeDecode(SHA,256,length(Content),Encrypt,nil,nil,Pointer(Content),nil);
    if Len<0 then
      exit;
    SetString(Content,PAnsiChar(AES.outStreamCreated.Memory),Len);
    result := true;
  finally
    AES.OutStreamCreated.Free;
  end;
end;

procedure TEditForm.BtnPictureClick(Sender: TObject);
begin
  Rec.fPicture := '';
  with TOpenPictureDialog.Create(self) do
  try
    Title := BtnPicture.Hint;
    Filter := GraphicFilter(TGraphic);
    Options := [ofHideReadOnly,ofPathMustExist,ofFileMustExist,ofEnableSizing];
    if Execute then
      LoadPicture(FileName,RawByteString(Rec.fPicture));
  finally
    Free;
  end;
end;

function TEditForm.LoadPicture(const FileName: TFileName; var Picture: RawByteString): boolean;
var Pic: TSynPicture;
begin
  result := false;
  if not FileExists(FileName) then
    exit;
  Pic := TSynPicture.Create;
  try
    Pic.LoadFromFile(FileName);
    if Pic.Empty then
      exit;
    SaveAsRawByteString(Pic,Picture,gptJPG,80,300);
    result := true;
  finally
    Pic.Free;
  end;
end;


initialization
  Gdip.RegisterPictures;
end.
