tags:

views:

143

answers:

4

Depending on the chosen filter, I'd like the OpenDialog to 'look' in different directries. Something like:

procedure TForm1.FileOpen1OpenDialogTypeChange(Sender: TObject);
// This does not work as intended...
var
  Dialog: TOpenDialog;
  FilterIndex: Integer;
  FilterExt: string;
  Path: string;
begin { TForm1.actFileOpenOpenDialogTypeChange }
  Dialog := Sender as TOpenDialog;
  FilterIndex := Dialog.FilterIndex;
  FilterExt := ExtFromFilter(Dialog.Filter, FilterIndex);
  GetIniPathForExtension(FilterExt, Path);
  if DirectoryExists(Path) and
     (Path <> IncludeTrailingPathDelimiter(Dialog.InitialDir)) then
  begin
    // those two statements don't have the desired effect
    // but illustrate what is meant to happen:
    Dialog.FileName := Path + '*' + FilterExt;
    Dialog.InitialDir := Path;
  end;
end;  { TForm1.actFileOpenOpenDialogTypeChange }

I can't find any way to let the dialog update itself to the new directory. I've tried calling OpenDialog.Execute, but that starts another OpenDialog without closing the current one...

+3  A: 

Some time ago I have looked after exactly that sort of thing, but couldn't find a solution either. Nowadays I'm glad not to implement it anyway for the following reason:

Imagine a user executes the open dialog. He knows where to find the required file and navigates to that folder. Now he can't see the file and realizes that the filter is set wrong. He changes the filter and naturally expects the folder to stay the same.

Try and make some observations: in most of the cases a user first selects the folder and after that the file type.

Uwe Raabe
A: 

One possibility:

var
  ShowAfterClose: boolean = false;
  MemFilterIndex: integer;

procedure TForm1.Import1Click(Sender: TObject);
begin
//...
  with OpenDialogImport do
  repeat
    if Execute then
    begin
      ReadImportedFile(FileName);                     //Do action
      exit;
    end else begin
      if not ShowAfterClose then                     //Check ShowAfterClose
        exit;
      ShowAfterClose := false;                       //Set ShowAfterClose false
      FilterIndex := MemFilterIndex;                 //Copy MemFilterIndex
    end;
  until false;
//...
end;

procedure TForm1.OpenDialogImportTypeChange(Sender: TObject);
begin
 PostMessage(TOpenDialog(Sender).handle,
   WM_KEYDOWN, VK_ESCAPE , 0);                        //Cancel dialog
 TOpenDialog(Sender).InitialDir := 'C:\';             //Set new directory
 MemFilterIndex := TOpenDialog(Sender).FilterIndex;   //Remember filter index
 ShowAfterClose := True;                              //ShowAfterClose = True
end;
GJ
When I test this, the PostMessage call does not make the dialog disappear. I've also tried it with SendMessage.Have you tested this yourself?
Reinier
Yes I'm and it works under D2007 and D5. Did you set event OpenDialogImportTypeChange?
GJ
well, it now works. D2010 on Windows 7.I have no idea why it didn't work yesterday.Apologies for questioning whether you tested it.
Reinier
A: 

I'll agree with everyone else to date... it's VERY BAD user interface design to change things without asking the user, and/or against the user's wishes.

Mike Warot
A: 

While the below is not exactly elegant, tested with 2K, XP, Vista and 7, it seems to work. The idea is to use the dialog's behavior that, when a valid directory is entered into the file name box, if 'Open' button is pressed, the dialog switches to that folder.

It does not work with 'Vista style' dialogs, I don't have any acquaintance with the Common Item Dialog. So the UseLatestCommonDialogs must be set to false before showing a dialog. Also note that the OnTypeChange event is not fired when the dialog is initially launched, one can set the FilterIndex and InitialDir before showing the dialog.

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure OpenDialog1TypeChange(Sender: TObject);
    procedure OpenDialog1FolderChange(Sender: TObject);
  private
    FDlgCleanUp: Boolean;
    FDlgFocusCtrl: HWnd;
    FSaveDlgFName: array [0..255] of Char;
  public
  end;

[...]

uses
  CommDlg, Dlgs;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    ShowMessage(OpenDialog1.FileName);
end;


type
  TFileExt = (feText = 1, feRichText, feDocument);

const
  FileExts: array [TFileExt] of string = ('txt', 'rtf', 'doc');
  FileExtDesc: array [TFileExt] of string =
      ('text (*.txt)', 'rich text (*.rtf)', 'document (*.doc)');

procedure TForm1.FormCreate(Sender: TObject);
var
  fe: TFileExt;
begin
  OpenDialog1.Options := OpenDialog1.Options - [ofOldStyleDialog];
  NewStyleControls := True;
  UseLatestCommonDialogs := False;

  OpenDialog1.Filter := '';
  for fe := Low(FileExts) to High(FileExts) do
    OpenDialog1.Filter := OpenDialog1.Filter +
        FileExtDesc[fe] + '|*.' + FileExts[fe] + '|';
end;

function GetIniPathForExtension(const Ext: string): string;
begin
  // Get corresponding path from an ini file....
  Result := ExtractFilePath(Application.ExeName) + Ext;
end;

procedure TForm1.OpenDialog1TypeChange(Sender: TObject);
var
  Dialog: TOpenDialog;
  Dlg: HWnd;
  Path: string;
begin
  Dialog := Sender as TOpenDialog;
  Dlg := GetParent(Dialog.Handle);
  Path := GetIniPathForExtension(FileExts[TFileExt(Dialog.FilterIndex)]);
  ForceDirectories(Path);

  // remember what's in file name, have to put it back later
  GetDlgItemText(Dlg, cmb13, @FSaveDlgFName, 256);
  SendMessage(GetDlgItem(Dlg, cmb13), WM_SETREDRAW, 0, 0); // reduce flicker
  FDlgFocusCtrl := GetFocus;

  // set file name to new folder
  SendMessage(Dlg, CDM_SETCONTROLTEXT, cmb13, Longint(PChar(Path)));

  // weird OS: windows - the below is only necessary for XP. 2K, Vista and 7
  // clicks fine without it, XP does not!
  windows.SetFocus(GetDlgItem(Dlg, IDOK));

  // do not cleanup here, with Vista and 7 folder change seems to happen
  // asynchronously - it might occur later than setting the file name and that
  // clears/reverts the edit box.
  FDlgCleanUp := True;

  // click 'Open' to change to folder
  SendMessage(GetDlgItem(Dlg, IDOK), BM_CLICK, IDOK, 0);
end;

procedure TForm1.OpenDialog1FolderChange(Sender: TObject);
var
  Dlg: HWnd;
begin
  // set the file name and focus back
  if FDlgCleanup then begin   // do not intervene if we didn't cause the change
    Dlg := GetParent((Sender as TOpenDialog).Handle);
    SendMessage(GetDlgItem(Dlg, cmb13), WM_SETREDRAW, 1, 0);
    SetDlgItemText(Dlg, cmb13, @FSaveDlgFName);
    windows.SetFocus(FDlgFocusCtrl);
  end;
  FDlgCleanup := False;
end;
Sertac Akyuz