Componentes.Terceros.jcl/official/1.96/experts/favfolders/OpenDlgFavAdapter.pas

551 lines
17 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is OpenDlgFavAdapter.pas. }
{ }
{ The Initial Developer of the Original Code is Petr Vones. }
{ Portions created by Petr Vones are Copyright (C) Petr Vones. All rights reserved. }
{ }
{ Contributor(s): }
{ Salvatore Besso }
{ }
{**************************************************************************************************}
{ }
{ Unit owner: Petr Vones }
{ }
{**************************************************************************************************}
// Last modified: $Date: 2005/12/26 18:03:41 $
// For history see end of file
unit OpenDlgFavAdapter;
interface
{$I jcl.inc}
uses
Windows, Messages, Classes, SysUtils, Controls, StdCtrls, ExtCtrls,
JclPeImage;
type
TFavOpenDialog = class (TObject)
private
FAddButton: TButton;
FDeleteMode: Boolean;
FDisableHelpButton: Boolean;
FDisablePlacesBar: Boolean;
FFavoriteComboBox: TComboBox;
FFavoriteFolders: TStrings;
FFavoritePanel: TPanel;
FHandle: HWND;
FHooks: TJclPeMapImgHooks;
FIsOpenPictDialog: Boolean;
FParentWnd: HWND;
FParentWndInstance: Pointer;
FOldParentWndInstance: Pointer;
FPictureDialogLastFolder: string;
FWndInstance: Pointer;
FOldWndInstance: Pointer;
FOnClose: TNotifyEvent;
FOnShow: TNotifyEvent;
procedure AddButtonClick(Sender: TObject);
procedure FavoriteComboBoxClick(Sender: TObject);
function GetCurrentFolder: string;
function GetFileNameEditWnd: HWND;
procedure SetCurrentFolder(const Value: string);
procedure SetDeleteMode(const Value: Boolean);
protected
procedure AdjustControlPos;
procedure DialogFolderChange;
procedure DialogShow;
procedure DoClose;
procedure DoShow;
procedure ParentWndProc(var Message: TMessage); virtual;
procedure WndProc(var Message: TMessage); virtual;
property CurrentFolder: string read GetCurrentFolder write SetCurrentFolder;
property DeleteMode: Boolean read FDeleteMode write SetDeleteMode;
property FileNameEditWnd: HWND read GetFileNameEditWnd;
public
constructor Create;
destructor Destroy; override;
procedure HookDialogs;
procedure LoadFavorites(const FileName: string);
procedure UnhookDialogs;
property DisableHelpButton: Boolean read FDisableHelpButton write FDisableHelpButton;
property DisablePlacesBar: Boolean read FDisablePlacesBar write FDisablePlacesBar;
property FavoriteFolders: TStrings read FFavoriteFolders;
property IsOpenPictDialog: Boolean read FIsOpenPictDialog;
property PictureDialogLastFolder: string read FPictureDialogLastFolder write FPictureDialogLastFolder;
property OnClose: TNotifyEvent read FOnClose write FOnClose;
property OnShow: TNotifyEvent read FOnShow write FOnShow;
end;
function InitializeFavOpenDialog: TFavOpenDialog;
implementation
uses
{$IFNDEF RTL140_UP}
Forms,
{$ENDIF ~RTL140_UP}
CommDlg, Dlgs,
JclFileUtils, JclStrings, JclSysInfo, JclSysUtils,
JclOtaConsts, JclOtaResources, JclOtaUtils;
{$R FavDlg.res}
type
TGetOpenFileName = function (var OpenFile: TOpenFilename): Bool; stdcall;
var
OldGetOpenFileName: TGetOpenFileName;
OldGetSaveFileName: TGetOpenFileName;
OldExplorerHook: function(Wnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): UINT stdcall;
FavOpenDialog: TFavOpenDialog;
function NewExplorerHook(Wnd: HWnd; Msg: UINT; WParam: WPARAM; LParam: LPARAM): UINT; stdcall;
begin
Result := OldExplorerHook(Wnd, Msg, WParam, LParam);
if (Msg = WM_INITDIALOG) and Assigned(FavOpenDialog) then
begin
FavOpenDialog.FHandle := Wnd;
FavOpenDialog.FOldWndInstance := Pointer(SetWindowLong(Wnd, GWL_WNDPROC, Longint(FavOpenDialog.FWndInstance)));
CallWindowProc(FavOpenDialog.FWndInstance, Wnd, Msg, WParam, LParam);
end;
end;
procedure InitOpenFileStruct(var OpenFile: TOpenFilename);
var
InitDir: string;
begin
with OpenFile do
if Flags and OFN_EXPLORER <> 0 then
begin
if Assigned(FavOpenDialog) then
FavOpenDialog.FIsOpenPictDialog := False;
if Flags and OFN_ENABLETEMPLATE = 0 then
begin
OldExplorerHook := lpfnHook;
lpfnHook := NewExplorerHook;
lpTemplateName := FavDialogTemplateName;
hInstance := FindResourceHInstance(FindClassHInstance(TFavOpenDialog));
Flags := Flags or OFN_ENABLETEMPLATE;
if Assigned(FavOpenDialog) then
begin
if FavOpenDialog.DisableHelpButton then
Flags := Flags and (not OFN_SHOWHELP);
{$IFDEF DELPHI6_UP}
if FavOpenDialog.DisablePlacesBar and (lStructSize = SizeOf(TOpenFilename)) then
FlagsEx := FlagsEx or OFN_EX_NOPLACESBAR;
{$ENDIF DELPHI6_UP}
end;
end
else
if (StrIComp(lpTemplateName, OpenPictDialogTemplateName) = 0) and Assigned(FavOpenDialog) then
begin
FavOpenDialog.FIsOpenPictDialog := True;
OldExplorerHook := lpfnHook;
lpfnHook := NewExplorerHook;
InitDir := FavOpenDialog.PictureDialogLastFolder;
if DirectoryExists(InitDir) then
lpstrInitialDir := PChar(FavOpenDialog.PictureDialogLastFolder)
else
FavOpenDialog.PictureDialogLastFolder := '';
end;
end;
end;
function NewGetOpenFileName(var OpenFile: TOpenFilename): Bool; stdcall;
begin
InitOpenFileStruct(OpenFile);
Result := OldGetOpenFileName(OpenFile);
end;
function NewGetSaveFileName(var OpenFile: TOpenFilename): Bool; stdcall;
begin
InitOpenFileStruct(OpenFile);
Result := OldGetSaveFileName(OpenFile);
end;
function InitializeFavOpenDialog: TFavOpenDialog;
begin
if not Assigned(FavOpenDialog) then
FavOpenDialog := TFavOpenDialog.Create;
Result := FavOpenDialog;
end;
//=== { TFavOpenDialog } =====================================================
constructor TFavOpenDialog.Create;
begin
inherited Create;
FFavoriteFolders := TStringList.Create;
FHooks := TJclPeMapImgHooks.Create;
FParentWndInstance := MakeObjectInstance(ParentWndProc);
FWndInstance := MakeObjectInstance(WndProc);
FFavoritePanel := TPanel.Create(nil);
with FFavoritePanel do
begin
Name := 'FavoritePanel';
BevelOuter := bvNone;
Caption := '';
FullRepaint := False;
FFavoriteComboBox := TComboBox.Create(FFavoritePanel);
with FFavoriteComboBox do
begin
SetBounds(6, 14, 300, Height);
Style := csDropDownList;
Sorted := True;
OnClick := FavoriteComboBoxClick;
Parent := FFavoritePanel;
end;
with TStaticText.Create(FFavoritePanel) do
begin
AutoSize := False;
SetBounds(6, 0, 100, 14);
Caption := RsFavorites;
FocusControl := FFavoriteComboBox;
Parent := FFavoritePanel;
end;
FAddButton := TButton.Create(FFavoritePanel);
with FAddButton do
begin
SetBounds(333, 14, 75, 23);
Caption := RsAdd;
OnClick := AddButtonClick;
Parent := FFavoritePanel;
end;
end;
end;
destructor TFavOpenDialog.Destroy;
begin
UnhookDialogs;
FreeObjectInstance(FParentWndInstance);
FreeObjectInstance(FWndInstance);
FreeAndNil(FFavoritePanel);
FreeAndNil(FFavoriteFolders);
FreeAndNil(FHooks);
inherited Destroy;
end;
procedure TFavOpenDialog.AddButtonClick(Sender: TObject);
var
I: Integer;
Path: string;
begin
if DeleteMode then
begin
I := FFavoriteComboBox.ItemIndex;
Path := FFavoriteComboBox.Items[I];
if MessageBox(FHandle, PChar(Format(RsDelConfirm, [Path])), PChar(RsConfirmation),
MB_YESNO or MB_ICONQUESTION or MB_DEFBUTTON2) = ID_YES then
begin
FFavoriteComboBox.Items.Delete(I);
DeleteMode := False;
end;
end
else
begin
Path := CurrentFolder;
I := FFavoriteComboBox.Items.IndexOf(Path);
if I = -1 then
begin
FFavoriteComboBox.Items.Add(Path);
I := FFavoriteComboBox.Items.IndexOf(Path);
FFavoriteComboBox.ItemIndex := I;
DeleteMode := True;
end;
end;
end;
procedure TFavOpenDialog.AdjustControlPos;
var
ParentRect, FileNameEditRect, OkButtonRect: TRect;
procedure GetDlgItemRect(ItemID: Integer; var R: TRect);
begin
GetWindowRect(GetDlgItem(FParentWnd, ItemID), R);
MapWindowPoints(0, FParentWnd, R, 2);
end;
begin
GetWindowRect(FParentWnd, ParentRect);
if GetDlgItem(FParentWnd, edt1) <> 0 then
GetDlgItemRect(edt1, FileNameEditRect)
else
GetDlgItemRect(cmb1, FileNameEditRect);
GetDlgItemRect(1, OkButtonRect);
// Salvatore Besso: Changes to avoid truncation of Add button. I don't know why, but debugging I
// have discovered that ParentRect.Right was equal to 1024, ie Screen.Width. I also can't figure
// out why I can't preserve original help button that disappears using this expert.
// As visible in the changes, favorite panel width is just left of the original button column.
if IsWin2k or IsWinXP then
FAddButton.Width := 65;
FFavoritePanel.Width := OkButtonRect.Left - 1;
FFavoriteComboBox.Width := FFavoritePanel.Width - FFavoriteComboBox.Left - FAddButton.Width - 16;
FAddButton.Left := FFavoriteComboBox.Width + 14;
end;
procedure TFavOpenDialog.DialogFolderChange;
var
Path: string;
begin
Path := CurrentFolder;
with FFavoriteComboBox do
begin
ItemIndex := Items.IndexOf(Path);
DeleteMode := (ItemIndex <> -1);
end;
end;
procedure TFavOpenDialog.DialogShow;
var
PreviewRect: TRect;
begin
FParentWnd := GetParent(FHandle);
if IsOpenPictDialog then
DoShow
else
begin
GetClientRect(FHandle, PreviewRect);
PreviewRect.Top := PreviewRect.Bottom - 43;
FFavoritePanel.BoundsRect := PreviewRect;
FFavoritePanel.ParentWindow := FHandle;
if IsWin2k or IsWinXP then
FOldParentWndInstance := Pointer(SetWindowLong(FParentWnd, GWL_WNDPROC, Longint(FParentWndInstance)));
AdjustControlPos;
try
DoShow;
finally
FFavoriteComboBox.Items.Assign(FavoriteFolders);
end;
end;
end;
procedure TFavOpenDialog.DoClose;
begin
if Assigned(FOnClose) then
FOnClose(Self);
end;
procedure TFavOpenDialog.DoShow;
begin
if Assigned(FOnShow) then
FOnShow(Self);
end;
procedure TFavOpenDialog.FavoriteComboBoxClick(Sender: TObject);
begin
with FFavoriteComboBox do
if ItemIndex <> - 1 then
CurrentFolder := FFavoriteComboBox.Items[ItemIndex];
end;
function TFavOpenDialog.GetCurrentFolder: string;
var
Path: array [0..MAX_PATH] of Char;
begin
SetString(Result, Path, SendMessage(FParentWnd, CDM_GETFOLDERPATH, SizeOf(Path), Integer(@Path)));
StrResetLength(Result);
end;
function TFavOpenDialog.GetFileNameEditWnd: HWND;
begin
Result := GetDlgItem(FParentWnd, edt1);
if Result = 0 then
Result := GetDlgItem(FParentWnd, cmb13);
end;
procedure TFavOpenDialog.HookDialogs;
procedure HookImportsForModule(ModuleBase: Pointer);
const
comdlg32 = 'comdlg32.dll';
begin
if ModuleBase <> nil then
begin
FHooks.HookImport(ModuleBase, comdlg32, 'GetOpenFileNameA', @NewGetOpenFileName, @OldGetOpenFileName);
FHooks.HookImport(ModuleBase, comdlg32, 'GetSaveFileNameA', @NewGetSaveFileName, @OldGetSaveFileName);
end;
end;
var
Pe: TJclPeImage;
I: Integer;
HookedModule: LongWord;
begin
{ TODO : Hook all loaded modules }
Pe := TJclPeImage.Create(True);
try
HookedModule := FindClassHInstance(ClassType);
Pe.AttachLoadedModule(HookedModule);
if Pe.StatusOK then
begin
HookImportsForModule(Pointer(HookedModule));
for I := 0 to Pe.ImportList.UniqueLibItemCount - 1 do
HookImportsForModule(Pointer(GetModuleHandle(PChar(Pe.ImportList.UniqueLibItems[I].FileName))));
end;
finally
Pe.Free;
end;
end;
procedure TFavOpenDialog.LoadFavorites(const FileName: string);
begin
if FileExists(FileName) then
FavoriteFolders.LoadFromFile(FileName)
else
FavoriteFolders.Clear;
end;
procedure TFavOpenDialog.ParentWndProc(var Message: TMessage);
begin
with Message do
begin
Result := CallWindowProc(FOldParentWndInstance, FParentWnd, Msg, WParam, LParam);
if Msg = WM_SIZE then
AdjustControlPos;
end;
end;
procedure TFavOpenDialog.SetCurrentFolder(const Value: string);
var
LastFocus: HWND;
FileNameBuffer: string;
begin
if (FParentWnd <> 0) and DirectoryExists(Value) then
begin
LastFocus := GetFocus;
FileNameBuffer := GetWindowCaption(FileNameEditWnd);
SendMessage(FParentWnd, CDM_SETCONTROLTEXT, edt1, LPARAM(PChar(Value)));
SendMessage(GetDlgItem(FParentWnd, 1), BM_CLICK, 0, 0);
SendMessage(FParentWnd, CDM_SETCONTROLTEXT, edt1, LPARAM(PChar(FileNameBuffer)));
SetFocus(LastFocus);
end;
end;
procedure TFavOpenDialog.SetDeleteMode(const Value: Boolean);
begin
if FDeleteMode <> Value then
begin
FDeleteMode := Value;
if FDeleteMode then
FAddButton.Caption := RsDelete
else
FAddButton.Caption := RsAdd;
FFavoriteComboBox.Invalidate;
end;
end;
procedure TFavOpenDialog.UnhookDialogs;
var
I: Integer;
begin
I := 0;
while I < FHooks.Count do
if not FHooks[I].Unhook then
Inc(I);
end;
procedure TFavOpenDialog.WndProc(var Message: TMessage);
procedure Default;
begin
with Message do
Result := CallWindowProc(FOldWndInstance, FHandle, Msg, WParam, LParam);
end;
begin
if FHandle <> 0 then
begin
case Message.Msg of
WM_NOTIFY:
begin
case (POFNotify(Message.LParam)^.hdr.code) of
CDN_INITDONE:
DialogShow;
CDN_FOLDERCHANGE:
if not IsOpenPictDialog then
DialogFolderChange;
CDN_FILEOK:
if IsOpenPictDialog then
FPictureDialogLastFolder := CurrentFolder;
end;
Default;
end;
WM_DESTROY:
begin
if not IsOpenPictDialog then
FavoriteFolders.Assign(FFavoriteComboBox.Items);
try
DoClose;
Default;
finally
if not IsOpenPictDialog then
FFavoritePanel.ParentWindow := 0;
FParentWnd := 0;
end;
end;
WM_NCDESTROY:
begin
Default;
FHandle := 0;
end;
else
Default;
end;
end;
end;
initialization
finalization
try
FreeAndNil(FavOpenDialog);
except
on ExceptionObj: TObject do
begin
JclExpertShowExceptionDialog(ExceptionObj);
raise;
end;
end;
// History:
// $Log: OpenDlgFavAdapter.pas,v $
// Revision 1.4 2005/12/26 18:03:41 outchy
// Enhanced bds support (including C#1 and D8)
// Introduction of dll experts
// Project types in templates
//
// Revision 1.3 2005/12/16 23:46:25 outchy
// Added expert stack form.
// Added code to display call stack on expert exception.
// Fixed package extension for D2006.
//
// Revision 1.2 2005/10/21 12:24:41 marquardt
// experts reorganized with new directory common
//
// Revision 1.1 2005/10/03 16:27:37 rrossmair
// - moved over from jcl\examples\vcl\idefavopendialogs
//
// Revision 1.5 2005/02/26 17:36:01 rrossmair
// - applied Salvatore Besso's fix for truncation of Add button when using large fonts.
// - some cleaning, module header updated.
//
end.