win32: simplify FileDialog handling:

- always use our own buffer for file names
  - invoke DoSelectionChange on file selection changed
  - update dialog Files, FileName props on selection change

git-svn-id: trunk@16845 -
This commit is contained in:
paul 2008-10-02 10:01:49 +00:00
parent 36f21372de
commit 771a7ee01f

View File

@ -56,6 +56,14 @@ uses
Win32Proc;
type
TOpenFileDialogRec = record
Dialog: TFileDialog;
AnsiFolderName: string;
AnsiFileNames: string;
UnicodeFolderName: widestring;
UnicodeFileNames: widestring
end;
POpenFileDialogRec = ^TOpenFileDialogRec;
{ TWin32WSCommonDialog }
@ -130,19 +138,11 @@ type
class function CreateHandle(const ACommonDialog: TCommonDialog): THandle; override;
end;
function OpenFileDialogCallBack(hWnd: Handle; uMsg: UINT; wParam: WPARAM;
lParam: LPARAM): UINT; stdcall;
implementation
type
TOpenFileDialogRec = record
Dialog: TFileDialog;
AnsiFolderName: string;
AnsiFileNames: string;
UnicodeFolderName: widestring;
UnicodeFileNames: widestring
end;
POpenFileDialogRec = ^TOpenFileDialogRec;
// The size of the OPENFILENAME record depends on the windows version
// In the initialization section the correct size is determined.
var
@ -167,6 +167,93 @@ begin
Move(PChar(AnsiChars)^, Result^, length(AnsiChars)+1);
end;
procedure UpdateFileProperties(OpenFile: LPOPENFILENAME);
var
DialogRec: POpenFileDialogRec;
AOpenDialog: TOpenDialog;
procedure SetFilesPropertyCustomFiles(AFiles:TStrings);
var
i, Start: integer;
FolderName: string;
FileNames: String;
begin
{$ifdef WindowsUnicodeSupport}
if UnicodeEnabledOS then
begin
FolderName := UTF8Encode(DialogRec^.UnicodeFolderName);
FileNames := UTF8Encode(DialogRec^.UnicodeFileNames);
end
else
begin
FolderName := AnsiToUtf8(DialogRec^.AnsiFolderName);
FileNames := AnsiToUtf8(DialogRec^.AnsiFileNames);
end;
{$else}
FolderName:= DialogRec^.AnsiFolderName;
FileNames := DialogRec^.AnsiFileNames;
{$endif}
FolderName := AppendPathDelim(FolderName);
if (Length(FileNames) > 0) and (FileNames[1] = '"') then
begin
Start := 1; // first quote is on pos 1
while FileNames[Start] <> #0 do
begin
i := Start + 1;
while FileNames[i] <> '"' do
inc(i);
AFiles.Add(FolderName + Copy(FileNames, Start + 1, I - Start - 1));
start := i+1;
while (FileNames[Start] <> #0) and (FileNames[start] <> '"') do
inc(Start);
end;
end
else
AFiles.Add(FolderName + FileNames);
end;
procedure SetFilesPropertyForOldStyle(AFiles:TStrings);
var
SelectedStr: string;
FolderName: string;
I,Start: integer;
begin
{$ifdef WindowsUnicodeSupport}
if UnicodeEnabledOS then
SelectedStr:=UTF8Encode(widestring(PWideChar(OpenFile^.lpStrFile)))
else
SelectedStr:=AnsiToUtf8(OpenFile^.lpStrFile);
{$else}
SelectedStr:=OpenFile^.lpStrFile;
{$endif}
if not (ofAllowMultiSelect in AOpenDialog.Options) then
AFiles.Add(SelectedStr)
else begin
Start:=Pos(' ',SelectedStr);
FolderName := copy(SelectedStr,1,start-1);
SelectedStr:=SelectedStr+' ';
inc(start);
for I:= Start to Length(SelectedStr) do
if SelectedStr[I] = ' ' then
begin
AFiles.Add(ExpandFileNameUTF8(FolderName+Copy(SelectedStr,Start,I - Start)));
Start:=Succ(I);
end;
end;
end;
begin
DialogRec := POpenFileDialogRec(OpenFile^.lCustData);
AOpenDialog := TOpenDialog(DialogRec^.Dialog);
AOpenDialog.Files.Clear;
AOpenDialog.FilterIndex := OpenFile^.nFilterIndex;
if (ofOldStyleDialog in AOpenDialog.Options) then
SetFilesPropertyForOldStyle(AOpenDialog.Files)
else
SetFilesPropertyCustomFiles(AOpenDialog.Files);
AOpenDialog.FileName := AOpenDialog.Files[0];
end;
{------------------------------------------------------------------------------
Method: GetOwnerHandle
Params: ADialog - dialog to get 'guiding parent' window handle for
@ -334,61 +421,44 @@ begin
begin
FolderSize := CommDlg_OpenSave_GetFolderPathW(GetParent(hwnd), nil, 0);
FilesSize := CommDlg_OpenSave_GetSpecW(GetParent(hwnd), nil, 0);
SetLength(DialogRec^.UnicodeFolderName, FolderSize-1);
CommDlg_OpenSave_GetFolderPathW(GetParent(hwnd),
PWideChar(DialogRec^.UnicodeFolderName),
FolderSize);
// test if we need to use our own storage
if (SizeInt(OpenFileName^.nMaxFile) < FolderSize + FilesSize) and
(OpenFileName^.lCustData <> 0) then
begin
SetLength(DialogRec^.UnicodeFolderName, FolderSize-1);
CommDlg_OpenSave_GetFolderPathW(GetParent(hwnd),
PWideChar(DialogRec^.UnicodeFolderName),
FolderSize);
if length(DialogRec^.UnicodeFileNames) < FilesSize then
// allocate twice the size, to prevent much relocations
SetLength(DialogRec^.UnicodeFileNames, FilesSize*2);
CommDlg_OpenSave_GetSpecW(GetParent(hwnd),
PWideChar(DialogRec^.UnicodeFileNames),
Length(DialogRec^.UnicodeFileNames));
end;
SetLength(DialogRec^.UnicodeFileNames, FilesSize - 1);
CommDlg_OpenSave_GetSpecW(GetParent(hwnd),
PWideChar(DialogRec^.UnicodeFileNames),
FilesSize);
end else
begin
FolderSize := CommDlg_OpenSave_GetFolderPath(GetParent(hwnd), nil, 0);
FilesSize := CommDlg_OpenSave_GetSpec(GetParent(hwnd), nil, 0);
// test if we need to use our own storage
if (SizeInt(OpenFileName^.nMaxFile) < FolderSize + FilesSize) and
(OpenFileName^.lCustData <> 0) then
begin
SetLength(DialogRec^.AnsiFolderName, FolderSize-1);
CommDlg_OpenSave_GetFolderPath(GetParent(hwnd),
PChar(DialogRec^.AnsiFolderName), FolderSize);
SetLength(DialogRec^.AnsiFolderName, FolderSize-1);
CommDlg_OpenSave_GetFolderPath(GetParent(hwnd),
PChar(DialogRec^.AnsiFolderName),
FolderSize);
if length(DialogRec^.AnsiFileNames) < FilesSize then
// allocate twice the size, to prevent much relocations
SetLength(DialogRec^.AnsiFileNames, FilesSize*2);
CommDlg_OpenSave_GetSpec(GetParent(hwnd),
PChar(DialogRec^.AnsiFileNames), Length(DialogRec^.AnsiFileNames));
end;
SetLength(DialogRec^.AnsiFileNames, FilesSize - 1);
CommDlg_OpenSave_GetSpec(GetParent(hwnd),
PChar(DialogRec^.AnsiFileNames),
FilesSize);
end;
{$else}
FolderSize := CommDlg_OpenSave_GetFolderPath(GetParent(hwnd), nil, 0);
FilesSize := CommDlg_OpenSave_GetSpec(GetParent(hwnd), nil, 0);
// test if we need to use our own storage
if (SizeInt(OpenFileName^.nMaxFile) < FolderSize + FilesSize) and
(OpenFileName^.lCustData <> 0) then
begin
SetLength(DialogRec^.AnsiFolderName, FolderSize-1);
CommDlg_OpenSave_GetFolderPath(GetParent(hwnd),
PChar(DialogRec^.AnsiFolderName), FolderSize);
SetLength(DialogRec^.AnsiFolderName, FolderSize-1);
CommDlg_OpenSave_GetFolderPath(GetParent(hwnd),
PChar(DialogRec^.AnsiFolderName),
FolderSize);
if length(DialogRec^.AnsiFileNames) < FilesSize then
// allocate twice the size, to prevent much relocations
SetLength(DialogRec^.AnsiFileNames, FilesSize*2);
CommDlg_OpenSave_GetSpec(GetParent(hwnd),
PChar(DialogRec^.AnsiFileNames), Length(DialogRec^.AnsiFileNames));
end;
SetLength(DialogRec^.AnsiFileNames, FilesSize - 1);
CommDlg_OpenSave_GetSpec(GetParent(hwnd),
PChar(DialogRec^.AnsiFileNames),
FilesSize);
{$endif}
UpdateFileProperties(OpenFileName);
TOpenDialog(DialogRec^.Dialog).DoSelectionChange;
end;
CDN_TYPECHANGE:
begin
@ -538,166 +608,19 @@ end;
procedure ProcessFileDialogResult(AOpenDialog: TOpenDialog; UserResult: WordBool);
var
DialogRec: POpenFileDialogRec;
OpenFile: LPOPENFILENAME;
procedure SetFilesProperty(AFiles:TStrings);
var
I: integer;
pName: PChar;
{$ifdef WindowsUnicodeSupport}
PWideName: PWideChar;
DirName: string;
{$endif WindowsUnicodeSupport}
begin
{$ifdef WindowsUnicodeSupport}
if UnicodeEnabledOS then
begin
PWideName := PWideChar(OpenFile^.lpStrFile);
I:=Length(PWideName);
if I < OpenFile^.nFileOffset then
begin
DirName := AppendPathDelim(UTF8Encode(widestring(PWideName)));
Inc(PWideName, Succ(I));
I:=Length(PWideName);
while I > 0 do
begin
// Don't use expand filename here, it expands directories using
// system encoding, not UTF-8
AFiles.Add(DirName + Utf8Encode(widestring(PWideName)));
Inc(PWideName,Succ(I));
I:=Length(PWideName);
end;
end
else
AFiles.Add(Utf8Encode(widestring(PWideName)));
end
else
begin
pName := OpenFile^.lpStrFile;
I:=Length(pName);
if I < OpenFile^.nFileOffset then
begin
DirName := AppendPathDelim(AnsiToUtf8(pName));
Inc(pName,Succ(I));
I:=Length(pName);
while I > 0 do
begin
AFiles.Add(DirName + AnsiToUtf8(pName));
Inc(pName,Succ(I));
I:=Length(pName);
end;
end
else
AFiles.Add(StrPas(pName));
end;
{$else}
pName := OpenFile^.lpStrFile;
I:=Length(pName);
if I < OpenFile^.nFileOffset then
begin
Inc(pName,Succ(I));
I:=Length(pName);
while I > 0 do
begin
AFiles.Add(ExpandFileNameUTF8(StrPas(pName)));
Inc(pName,Succ(I));
I:=Length(pName);
end;
end
else
AFiles.Add(StrPas(pName));
{$endif}
end;
procedure SetFilesPropertyCustomFiles(AFiles:TStrings);
var
i, Start: integer;
FolderName: string;
FileNames: String;
begin
{$ifdef WindowsUnicodeSupport}
if UnicodeEnabledOS then begin
FolderName := UTF8Encode(DialogRec^.UnicodeFolderName);
FileNames := UTF8Encode(DialogRec^.UnicodeFileNames);
end else begin
FolderName := AnsiToUtf8(DialogRec^.AnsiFolderName);
FileNames := AnsiToUtf8(DialogRec^.AnsiFileNames);
end;
{$else}
FolderName:= DialogRec^.AnsiFolderName;
FileNames := DialogRec^.AnsiFileNames;
{$endif}
FolderName := AppendPathDelim(FolderName);
if (FileNames[1] = '"') then
begin
Start := 1; // first quote is on pos 1
while FileNames[Start] <> #0 do
begin
i := Start + 1;
while FileNames[i] <> '"' do
inc(i);
AFiles.Add(FolderName + Copy(FileNames, Start + 1, I - Start - 1));
start := i+1;
while (FileNames[Start] <> #0) and (FileNames[start] <> '"') do
inc(Start);
end;
end;
end;
procedure SetFilesPropertyForOldStyle(AFiles:TStrings);
var
SelectedStr: string;
FolderName: string;
I,Start: integer;
begin
{$ifdef WindowsUnicodeSupport}
if UnicodeEnabledOS then
SelectedStr:=UTF8Encode(widestring(PWideChar(OpenFile^.lpStrFile)))
else
SelectedStr:=AnsiToUtf8(OpenFile^.lpStrFile);
{$else}
SelectedStr:=OpenFile^.lpStrFile;
{$endif}
if not (ofAllowMultiSelect in AOpenDialog.Options) then
AFiles.Add(SelectedStr)
else begin
Start:=Pos(' ',SelectedStr);
FolderName := copy(SelectedStr,1,start-1);
SelectedStr:=SelectedStr+' ';
inc(start);
for I:= Start to Length(SelectedStr) do
if SelectedStr[I] = ' ' then
begin
AFiles.Add(ExpandFileNameUTF8(FolderName+Copy(SelectedStr,Start,I - Start)));
Start:=Succ(I);
end;
end;
end;
var
BufferTooSmall: boolean;
begin
OPENFILE := LPOPENFILENAME(AOpenDialog.Handle);
DialogRec := POpenFileDialogRec(OPENFILE^.lCustData);
BufferTooSmall := not UserResult and (CommDlgExtendedError=FNERR_BUFFERTOOSMALL);
if BufferTooSmall then
UserResult := true;
if not UserResult and (CommDlgExtendedError = FNERR_BUFFERTOOSMALL) then
UserResult := True;
SetDialogResult(AOpenDialog, UserResult);
AOpenDialog.Files.Clear;
if UserResult then
if UserResult then
UpdateFileProperties(OPENFILE)
else
begin
AOpenDialog.FilterIndex := OpenFile^.nFilterIndex;
if (ofOldStyleDialog in AOpenDialog.Options) then
SetFilesPropertyForOldStyle(AOpenDialog.Files)
else if BufferTooSmall then
SetFilesPropertyCustomFiles(AOpenDialog.Files)
else
SetFilesProperty(AOpenDialog.Files);
AOpenDialog.FileName := AOpenDialog.Files[0];
end else
AOpenDialog.Files.Clear;
AOpenDialog.FileName := '';
end;
end;
{ TWin32WSOpenDialog }
@ -902,7 +825,7 @@ begin
if length(InitialDir)=0 then
InitialDir := TSelectDirectoryDialog(ACommonDialog).InitialDir;
if length(InitialDir)>0 then begin
// remove the \ at the end. +
// remove the \ at the end.
if Copy(InitialDir,length(InitialDir),1)=PathDelim then
InitialDir := copy(InitialDir,1, length(InitialDir)-1);
// if it is a rootdirectory, then the InitialDir must have a \ at the end.