unit uConfirmations;
{$INCLUDE 'DirSync.inc'}

interface

uses
  SysUtils, Windows, Classes,
  {$IFDEF FAR3} Plugin3, {$ELSE} PluginW, {$ENDIF} FarKeysW, FarColor,
  uSystem, uFAR, uLog,
  uDirSyncConsts, uMessages, uOptions, uCompatibility;

type
  TConfirmationDialogButton = (ocbYes, ocbYesToAll, ocbNo, ocbNoToAll, ocbCompare, ocbCancel);
  TWhatToDoWithDifferentFilesDialogButton = (dfbOverwriteLeft, dfbOverwriteRight, dfbSkip, dfbCompare, dfbAlwaysOverwriteLeft, dfbAlwaysOverwriteRight, dfbAlwaysSkip, dfbCancel);

  TConfirmationDialog = class(TFarDialog)
  private
    fCheckRemember: integer;
    fButtonYes: integer;
    fButtonNo: integer;
    fButtonCompare: integer;
    fButtonCancel: integer;
  protected
    function GetButtonCaption(Button: TConfirmationDialogButton): PFarChar; virtual;
    function GetMessage: PFarChar; virtual;
    function GetFileInfo(MessageID: TMessages; const FileName: string; Width: integer): string;
    function GetHeight: integer; virtual;
    function GetWidth: integer; virtual;
    function HasCompareButton: boolean; virtual;
    procedure BuildDialog; virtual;
    procedure BuildDialogTitle; virtual;
    procedure BuildDialogContents; virtual;
    procedure BuildDialogButtons; virtual;
  public
    procedure ClearDialog; override;
    function Execute: TConfirmationDialogButton;
  end;

  TOverwriteConfirmationDialog = class(TConfirmationDialog)
  private
    fSourceFileName: string;
    fDestinationFileName: string;
    fFromRightToLeft: boolean;
    fReadOnlyDestination: boolean;
  protected
    function GetButtonCaption(Button: TConfirmationDialogButton): PFarChar; override;
    function GetMessage: PFarChar; override;
    function GetHeight: integer; override;
    function HasCompareButton: boolean; override;
    procedure BuildDialogContents; override;
  public
    constructor Create;
    property FromRightToLeft: boolean read fFromRightToLeft write fFromRightToLeft;
    property ReadOnlyDestination: boolean read fReadOnlyDestination write fReadOnlyDestination;
    property SourceFileName: string read fSourceFileName write fSourceFileName;
    property DestinationFileName: string read fDestinationFileName write fDestinationFileName;
  end;

  TDeleteConfirmationDialog = class(TConfirmationDialog)
  private
    fFileName: string;
    fFileOnLeft: boolean;
    fReadOnlyFile: boolean;
    fIsDirectory: boolean;
  protected
    function GetButtonCaption(Button: TConfirmationDialogButton): PFarChar; override;
    function GetMessage: PFarChar; override;
    function GetHeight: integer; override;
    procedure BuildDialogContents; override;
  public
    constructor Create;
    property FileOnLeft: boolean read fFileOnLeft write fFileOnLeft;
    property ReadOnlyFile: boolean read fReadOnlyFile write fReadOnlyFile;
    property FileName: string read fFileName write fFileName;
    property IsDirectory: boolean read fIsDirectory write fIsDirectory;
  end;

  TWhatToDoWithDifferentFilesDialog = class(TFarDialog)
  private
    fLeftFileName: string;
    fRightFileName: string;
  private
    fCheckRemember: integer;
    fButtonOverwriteLeft: integer;
    fButtonOverwriteRight: integer;
    fButtonSkip: integer;
    fButtonCompare: integer;
    fButtonCancel: integer;
  protected
    function GetHeight: integer;
    function GetWidth: integer;
    procedure BuildDialog; virtual;
  public
    constructor Create;
    procedure ClearDialog; override;
    function Execute: TWhatToDoWithDifferentFilesDialogButton;
    property LeftFileName: string read fLeftFileName write fLeftFileName;
    property RightFileName: string read fRightFileName write fRightFileName;
  end;

implementation

{ TConfirmationDialog }

procedure TConfirmationDialog.BuildDialog;
begin
  // Build the dialog
  ClearDialog;
  BuildDialogTitle;
  BuildDialogContents;
  BuildDialogButtons;
  // Set the defaultbutton
  {$IFDEF FAR3}
  Items[fButtonYes].Flags := Items[fButtonYes].Flags or DIF_DEFAULTBUTTON;
  {$ELSE}
  Items[fButtonYes].DefaultButton := 1;
  {$ENDIF}
end;

procedure TConfirmationDialog.BuildDialogButtons;
begin
                     AddLabel    (  4,  GetHeight-4, GetWidth-2, nil,                           DIF_SEPARATOR);
  fCheckRemember :=  AddCheckBox (  5,  GetHeight-3,             GetMsg(MRememberChoice),       False, 0);
                     AddLabel    (  4,  GetHeight-2, GetWidth-2, nil,                           DIF_SEPARATOR);
  fButtonYes :=      AddButton   (  0,  GetHeight-1,             GetButtonCaption(ocbYes),      DIF_CENTERGROUP);
  fButtonNo :=       AddButton   (  0,  GetHeight-1,             GetButtonCaption(ocbNo),       DIF_CENTERGROUP);
  if HasCompareButton then
    fButtonCompare :=  AddButton   (  0,  GetHeight-1,             GetButtonCaption(ocbCompare),  DIF_CENTERGROUP);
  fButtonCancel :=   AddButton   (  0,  GetHeight-1,             GetButtonCaption(ocbCancel),   DIF_CENTERGROUP);
end;

procedure TConfirmationDialog.BuildDialogContents;
begin
end;

procedure TConfirmationDialog.BuildDialogTitle;
begin
  AddDoubleBox(  3,  1, GetWidth+2, GetHeight, GetMsg(MCmpTitle), 0);
  AddLabel    (  5,  2, GetWidth-4,            GetMessage,        DIF_CENTERTEXT);
end;

procedure TConfirmationDialog.ClearDialog;
begin
  inherited;
  fCheckRemember := -1;
  fButtonYes := -1;
  fButtonNo := -1;
  fButtonCompare := -1;
  fButtonCancel := -1;
end;

function TConfirmationDialog.Execute: TConfirmationDialogButton;
var
  Button: integer;
  Remember: boolean;
begin
  Result := ocbCancel;
  BuildDialog;
  if Build(-1, -1, GetWidth+6, GetHeight+2, FDLG_WARNING, 'Overwrite') then begin
    if inherited Execute(Button) then begin
      Remember := ItemChecked[fCheckRemember];
      if Button = fButtonYes then
        if Remember then
          Result := ocbYesToAll
        else
          Result := ocbYes
      else if Button = fButtonNo then
        if Remember then
          Result := ocbNoToAll
        else
          Result := ocbNo
      else if HasCompareButton and (Button = fButtonCompare) then
        Result := ocbCompare
      else
        Result := ocbCancel;
    end;
  end;
end;

function TConfirmationDialog.GetButtonCaption(Button: TConfirmationDialogButton): PFarChar;
begin
{
  case Button of
    ocbYes:      Result := GetMsg(MYes);
    ocbYesToAll: Result := GetMsg(MYesToAll);
    ocbNo:       Result := GetMsg(MNo);
    ocbNoToAll:  Result := GetMsg(MNoToAll);
    ocbCancel:   Result := GetMsg(MCancel);
    else         Result := nil;
  end;
}
  Result := nil;
end;

function TConfirmationDialog.GetFileInfo(MessageID: TMessages; const FileName: string; Width: integer): string;
var
  Attr: DWORD;
  Size: int64;
  CTime, MTime, ATime: TDateTime;
  sSize, sDate: string;
begin
  //Log('GetFileInfo for %s', [FileName]);
  Attr := GetFileAttributes(PChar(FileName));
  //Log('- Attributes = 0x%08.8x', [Attr]);
  if (Attr <> INVALID_FILE_ATTRIBUTES) and ((Attr and FILE_ATTRIBUTE_DIRECTORY) <> 0) then
    sSize := string(GetMsg(MDirectory))
  else begin
    Size := GetFileSize(FileName);
    //Log('- Size = %d', [Size]);
    if Size >= 1000000000000 then
      sSize := FormatCurr('###,###,##0" MiB"', Size div $100000)
    else if Size >= 0 then
      sSize := FormatCurr('###,###,###,##0', Size)
    else
      sSize := '?';
  end;
  if GetFileDateTime(FileName, CTime, MTime, ATime) then
    sDate := FormatDateTime('dd.mm.yyyy hh:nn:ss', MTime)
  else
    sDate := '?';
  Result := Format('%-*.*s   %15.15s %21.21s', [Width-40, Width-40, string(GetMsg(MessageID)), sSize, sDate]);
end;

function TConfirmationDialog.GetHeight: integer;
begin
  Result := 6;
end;

function TConfirmationDialog.GetMessage: PFarChar;
begin
  Result := nil;
end;

function TConfirmationDialog.GetWidth: integer;
begin
  Result := 70;
end;

function TConfirmationDialog.HasCompareButton: boolean;
begin
  Result := False;
end;

{ TOverwriteConfirmationDialog }

procedure TOverwriteConfirmationDialog.BuildDialogContents;
var
  FileName, SourceFileInfo, DestinationFileInfo: string;
begin
  inherited;
  FileName := TFarUtils.TruncateString(DestinationFileName, GetWidth-4, ' ');
  SourceFileInfo := GetFileInfo(MNew, SourceFileName, GetWidth-4);
  DestinationFileInfo := GetFileInfo(MExisting, DestinationFileName, GetWidth-4);
  AddLabel    (  5,  3, GetWidth-4,     PChar(FileName),            DIF_SHOWAMPERSAND);
  AddLabel    (  4,  4, GetWidth-2,     nil,                        DIF_SEPARATOR);
  AddLabel    (  5,  5, GetWidth-4,     PChar(SourceFileInfo),      DIF_SHOWAMPERSAND);
  AddLabel    (  5,  6, GetWidth-4,     PChar(DestinationFileInfo), DIF_SHOWAMPERSAND);
end;

constructor TOverwriteConfirmationDialog.Create;
begin
  inherited Create( {$IFDEF FAR3} PLUGIN_GUID, DIALOG_OVERWRITE_GUID {$ELSE} FarApi.ModuleNumber {$ENDIF} );
  fFromRightToLeft := False;
  fReadOnlyDestination := False;
end;

function TOverwriteConfirmationDialog.GetButtonCaption(Button: TConfirmationDialogButton): PFarChar;
begin
  case Button of
    ocbYes:      Result := GetMsg(MOverwrite);
    ocbYesToAll: Result := GetMsg(MOverwriteAll);
    ocbNo:       Result := GetMsg(MSkip);
    ocbNoToAll:  Result := GetMsg(MSkipAll);
    ocbCompare:  Result := GetMsg(MCompare);
    ocbCancel:   Result := GetMsg(MCancel);
    else         Result := nil;
  end;
end;

function TOverwriteConfirmationDialog.GetHeight: integer;
begin
  Result := 11;
end;

function TOverwriteConfirmationDialog.GetMessage: PFarChar;
begin
  if ReadOnlyDestination then
    if FromRightToLeft then
      Result := GetMsg(MLeftFileReadonly)
    else
      Result := GetMsg(MRightFileReadonly)
  else
    if FromRightToLeft then
      Result := GetMsg(MLeftFileAlreadyExists)
    else
      Result := GetMsg(MRightFileAlreadyExists)
end;

function TOverwriteConfirmationDialog.HasCompareButton: boolean;
begin
  Result := True;
end;

{ TDeleteConfirmationDialog }

procedure TDeleteConfirmationDialog.BuildDialogContents;
var
  FN, FileInfo: string;
begin
  inherited;
  //Log('TDeleteConfirmationDialog.BuildDialogContents');
  FN := TFarUtils.TruncateString(FileName, GetWidth-4, ' ');
  //Log(FN);
  if IsDirectory then
    FileInfo := GetFileInfo(MEraseDir, FileName, GetWidth-4)
  else
    FileInfo := GetFileInfo(MEraseFile, FileName, GetWidth-4);
  //Log(FileInfo);
  AddLabel    (  5,  3, GetWidth-4,     PChar(FN),            DIF_SHOWAMPERSAND);
  AddLabel    (  4,  4, GetWidth-2,     nil,                  DIF_SEPARATOR);
  AddLabel    (  5,  5, GetWidth-4,     PChar(FileInfo),      DIF_SHOWAMPERSAND);
end;

constructor TDeleteConfirmationDialog.Create;
begin
  inherited Create( {$IFDEF FAR3} PLUGIN_GUID, DIALOG_DELETE_GUID {$ELSE} FarApi.ModuleNumber {$ENDIF} );
  fFileOnLeft := False;
  fReadOnlyFile := False;
  fIsDirectory := False;
end;

function TDeleteConfirmationDialog.GetButtonCaption(Button: TConfirmationDialogButton): PFarChar;
begin
  case Button of
    ocbYes:      Result := GetMsg(MErase);
    ocbYesToAll: Result := GetMsg(MEraseAll);
    ocbNo:       Result := GetMsg(MSkip);
    ocbNoToAll:  Result := GetMsg(MSkipAll);
    ocbCancel:   Result := GetMsg(MCancel);
    else         Result := nil;
  end;
end;

function TDeleteConfirmationDialog.GetHeight: integer;
begin
  Result := 10;
end;

function TDeleteConfirmationDialog.GetMessage: PFarChar;
begin
  if ReadOnlyFile then
    if FileOnLeft then
      if IsDirectory then
        Result := GetMsg(MLeftDirReadonly)
      else
        Result := GetMsg(MLeftFileReadonly)
    else
      if IsDirectory then
        Result := GetMsg(MRightDirReadonly)
      else
        Result := GetMsg(MRightFileReadonly)
  else
    if FileOnLeft then
      if IsDirectory then
        Result := GetMsg(MLeftDirErase)
      else
        Result := GetMsg(MLeftFileErase)
    else
      if IsDirectory then
        Result := GetMsg(MRightDirErase)
      else
        Result := GetMsg(MRightFileErase)
end;

{ TWhatToDoWithDifferentFilesDialog }

procedure TWhatToDoWithDifferentFilesDialog.BuildDialog;
var
  LeftFN, RightFN: string;
begin
  LeftFN := TFarUtils.TruncateString(LeftFileName, GetWidth-4, ' ');
  RightFN := TFarUtils.TruncateString(RightFileName, GetWidth-4, ' ');
  // Build dialog
  ClearDialog;
                                 AddDoubleBox(3, 1, GetWidth+2, GetHeight, GetMsg(MCmpTitle), 0);
                                 AddLabel    (5, 2, GetWidth-4,            GetMsg(MFilesAreDifferent), DIF_CENTERTEXT);
                                 AddLabel    (4, 3, GetWidth-2, nil, DIF_SEPARATOR);
                                 AddLabel    (5, 4, GetMsg(MLeftFileName), 0);
                                 AddLabel    (5, 5, PFarChar(LeftFN), 0);
                                 AddLabel    (5, 6, GetMsg(MRightFileName), 0);
                                 AddLabel    (5, 7, PFarChar(RightFN), 0);
                                 AddLabel    (4, GetHeight-4, GetWidth-2, nil,               DIF_SEPARATOR);
  fCheckRemember :=              AddCheckBox (5, GetHeight-3, GetMsg(MRememberChoice),       False, 0);
                                 AddLabel    (4, GetHeight-2, GetWidth-2, nil, DIF_SEPARATOR);
  fButtonOverwriteLeft :=        AddButton   (0, GetHeight-1, GetMsg(MOverwriteLeft),        DIF_CENTERGROUP);
  fButtonOverwriteRight :=       AddButton   (0, GetHeight-1, GetMsg(MOverwriteRight),       DIF_CENTERGROUP);
  fButtonSkip :=                 AddButton   (0, GetHeight-1, GetMsg(MSkip),                 DIF_CENTERGROUP);
  fButtonCompare :=              AddButton   (0, GetHeight-1, GetMsg(MCompare),              DIF_CENTERGROUP);
  fButtonCancel :=               AddButton   (0, GetHeight-1, GetMsg(MCancel),               DIF_CENTERGROUP);
  // Set the defaultbutton
  {$IFDEF FAR3}
  Items[fButtonSkip].Flags := Items[fButtonSkip].Flags or DIF_DEFAULTBUTTON;
  {$ELSE}
  Items[fButtonSkip].DefaultButton := 1;
  {$ENDIF}
end;

procedure TWhatToDoWithDifferentFilesDialog.ClearDialog;
begin
  inherited;
  fCheckRemember := -1;
  fButtonOverwriteLeft := -1;
  fButtonOverwriteRight := -1;
  fButtonSkip := -1;
  fButtonCompare := -1;
  fButtonCancel := -1;
end;

constructor TWhatToDoWithDifferentFilesDialog.Create;
begin
  inherited Create( {$IFDEF FAR3} PLUGIN_GUID, DIALOG_DIFFERENTFILES_GUID {$ELSE} FarApi.ModuleNumber {$ENDIF} );
end;

function TWhatToDoWithDifferentFilesDialog.Execute: TWhatToDoWithDifferentFilesDialogButton;
var
  Button: integer;
  Remember: boolean;
begin
  Result := dfbCancel;
  BuildDialog;
  if Build(-1, -1, GetWidth+6, GetHeight+2, FDLG_WARNING, 'Different') then begin
    if inherited Execute(Button) then begin
      Remember := ItemChecked[fCheckRemember];
      if Button = fButtonOverwriteLeft then
        if Remember then
          Result := dfbAlwaysOverwriteLeft
        else
          Result := dfbOverwriteLeft
      else if Button = fButtonOverwriteRight then
        if Remember then
          Result := dfbAlwaysOverwriteRight
        else
          Result := dfbOverwriteRight
      else if Button = fButtonSkip then
        if Remember then
          Result := dfbAlwaysSkip
        else
          Result := dfbSkip
      else if Button = fButtonCompare then
        Result := dfbCompare
      else if Button = fButtonCancel then
        Result := dfbCancel;
    end;
  end;
end;

function TWhatToDoWithDifferentFilesDialog.GetHeight: integer;
begin
  Result := 12;
end;

function TWhatToDoWithDifferentFilesDialog.GetWidth: integer;
begin
  Result := 74;
end;

end.
