8

I created an (Delphi XE2) Firemonkey sample program which contains a TButton and a TSavedialog with two different filters. (The TSaveDialog component supports the Win32/Win64 and OS X platform.)

It works fine on Win32/Win64, but I don't now why it does not show the Savedialog filters on OS X (VirtualBox/OS X 10.7.x).

How can I get it to work on OS X ?

procedure TForm1.Button_SaveClick(Sender: TObject);
begin
  SaveDialog.Filter:='Format_1 (*.fmt1)|*.fmt1|Format_2 (*.fmt2)|*.fmt2';

  If Savedialog.Execute Then ShowMessage(SaveDialog.FileName+#13+'Selected filterindex: '+Inttostr(SaveDialog.FilterIndex));
end;
TLama
  • 75,147
  • 17
  • 214
  • 392

2 Answers2

3

The Save dialog is not constructed in Delphi but calls the native MAC OSX dialog (NSSavePanel). This does not have a user selectable filter.

When you execute a save dialog, Delphi passes the filter as an array to NSSavePanel.SetAllowedFileTypes which determines what extensions the OSX dialog will allow the user to specify - but there is no selectable list.

To allow the user to select from a list, you would need to create your own filetype selection dialog box and then take that selection and pass to the savedialog as the default file type and the only filter item.

The alternative of creating a completely new fileSave dialog is not easy as the Firemonkey tree component seems to insist on expanding all its nodes and hence performs a complete traverse of all the files on your hard drive. In any case, MAC users will be familiar with the standard dialog.

David Peters
  • 220
  • 1
  • 10
  • David, thank you for your very useful information, but I was not too happy when i read your answer. – Zoltan Karpati Oct 22 '12 at 11:48
  • I have an MS Windows 3D file format (geometry) viewer/converter ( http://web.t-online.hu/karpo ) that supports 615 different file formats (292 are for save!) and I am porting this program under FireMonkey to get Win32/Win64 and OS X executables. I think I will use a simple ComboBox for selecting format (and a second ComboBox for selecting from favourite formats) and a SaveDialog for selecting filename. – Zoltan Karpati Oct 22 '12 at 11:59
1

I had got the same problem with TOpendialog in MAC OSX: filter don't work, but in Windows they do. Now I solved the problem, perhaps you can use the code for your workaround. Those files which are NOT displayed in Windows are disabled under MAC OSX, you cannot select them.

uses
  Macapi.Foundation, Macapi.ObjectiveC, Macapi.AppKit;


 {$IFDEF MACOS}

  function AllocFilterStr(const S: string; var Filter: NSArray): Boolean;
  var
    input, pattern: string;
    FileTypes: array of string;
    outcome, aux: TArray<string>;
    i, j: Integer;
    FileTypesNS: array of Pointer;
    NStr: NSString;
    LocObj: ILocalObject;
  begin
    // First, split the string by using '|' as a separator
    Result := false;
    input := S;
    pattern := '\|';

    outcome := TRegEx.Split(input, pattern);
    pattern := '\*\.';
    SetLength(FileTypes, 0);

    for i := 0 to length(outcome) - 1 do
    begin
      if Odd(i) then
        if outcome[i] <> '*.*' then
          if AnsiLeftStr(outcome[i], 2) = '*.' then
          begin
            aux := TRegEx.Split(outcome[i], pattern);
            for j := 0 to length(aux) - 1 do
            begin
              aux[j] := Trim(aux[j]);
              if aux[j] <> '' then
              begin
                if AnsiEndsStr(';', aux[j]) then
                  aux[j] := AnsiLeftStr(aux[j], length(aux[j]) - 1);
                SetLength(FileTypes, length(FileTypes) + 1);
                FileTypes[length(FileTypes) - 1] := aux[j];
              end;
            end;
          end;
    end;

    // create the NSArray from the FileTypes array
    SetLength(FileTypesNS, length(FileTypes));
    for i := 0 to length(FileTypes) - 1 do
    begin
      NStr := NSSTR(FileTypes[i]);
      if Supports(NStr, ILocalObject, LocObj) then
        FileTypesNS[i] := LocObj.GetObjectID;
    end;
    if length(FileTypes) > 0 then begin
      Filter := TNSArray.Wrap(TNSArray.OCClass.arrayWithObjects(@FileTypesNS[0], length(FileTypes)));
      result := true;
    end;
  end;

function CFToDelphiString(const CFStr: CFStringRef): string;
var
  Range: CFRange;
begin
  Range.location := 0;
  Range.length := CFStringGetLength(CFStr);
  SetLength(Result, Range.length);
  if Range.length = 0 then Exit;
  CFStringGetCharacters(CFStr, Range, PWideChar(Result));
end;

function NSToDelphiString(const NSStr: NSString): string; inline;
begin
  Result := CFToDelphiString((NSStr as ILocalObject).GetObjectID);
end;


  {$ENDIF}


procedure TMainform.LoadClick(Sender: TObject);
 {$IFDEF MACOS}
var
  Filter: NSArray;
  LOpenDir: NSOpenPanel;
  {$ENDIF}
begin

  {$IFDEF MSWINDOWS}
  Opendialog1.Filter:= '*.fcb|*.fcb';
  if Opendialog1.execute then
  begin
    case Opendialog1.Filterindex of
      1:  LoadPlaylist(Opendialog1.filename, false, false);
      2:  LoadPlaylist(Opendialog1.filename, false, true);
    end;
  end;
  {$ENDIF}

 {$IFDEF MACOS}
  LOpenDir := TNSOpenPanel.Wrap(TNSOpenPanel.OCClass.openPanel);
  if AllocFilterStr('*.fcb|*.fcb', Filter) then
  if LOpenDir.runModalForTypes(Filter)=1 then
    LoadPlaylist(NSToDelphiString(LOpenDir.filename), false, false);
  {$ENDIF}
end;