Qt: new class TQtObjectDump for dumping complete object children tree, hooked TQtFileDialog children controls to add standard shortcuts which are missing in non-native qt dialogs.

git-svn-id: trunk@27262 -
This commit is contained in:
zeljko 2010-09-04 09:52:47 +00:00
parent 94c95314be
commit fd82ff4f5f
3 changed files with 437 additions and 3 deletions

View File

@ -724,6 +724,28 @@ type
property InReload: Boolean read FInReload;
end;
{TQtObjectDump}
TQtObjectDump = class(TObject) // helper class to dump complete children tree
private
FRoot: QObjectH;
FObjList: TFPList;
FList: TStrings;
procedure Iterator(ARoot: QObjectH);
procedure AddToList(AnObject: QObjectH);
public
constructor Create(AnObject: QObjectH);
destructor Destroy; override;
procedure DumpObject;
function findWidgetByName(const AName: WideString): QWidgetH;
function IsWidget(AnObject: QObjectH): Boolean;
function GetObjectName(AnObject: QObjectH): WideString;
function InheritsQtClass(AnObject: QObjectH; AQtClass: WideString): Boolean;
property List: TStrings read FList;
property ObjList: TFPList read FObjList;
end;
const
LCLQt_Destroy = QEventType(Ord(QEventUser) + $1000);
@ -4466,6 +4488,100 @@ begin
QActionGroup_setDisabled(FHandle, ADisabled);
end;
{ TQtObjectDump }
procedure TQtObjectDump.Iterator(ARoot: QObjectH);
var
i: Integer;
Children: TPtrIntArray;
begin
QObject_children(ARoot, @Children);
AddToList(ARoot);
for i := 0 to High(Children) do
Iterator(QObjectH(Children[i]))
end;
procedure TQtObjectDump.AddToList(AnObject: QObjectH);
// var
// ObjName: WideString;
begin
if AnObject <> nil then
begin
// QObject_objectName(AnObject, @ObjName);
if FObjList.IndexOf(AnObject) < 0 then
begin
FList.Add(dbghex(PtrUInt(AnObject)));
FObjList.Add(AnObject);
end else
raise Exception.Create('TQtObjectDump: Duplicated object in list '+dbghex(PtrUInt(AnObject)));
end;
end;
procedure TQtObjectDump.DumpObject;
begin
if FRoot = nil then
raise Exception.Create('TQtObjectDump: Invalid FRoot '+dbghex(PtrUInt(FRoot)));
Iterator(FRoot);
end;
function TQtObjectDump.findWidgetByName(const AName: WideString): QWidgetH;
var
j: Integer;
WS: WideString;
begin
Result := nil;
if AName = '' then
exit;
for j := 0 to FObjList.Count - 1 do
begin
QObject_objectName(QObjectH(FObjList.Items[j]), @WS);
if (WS = AName) and QObject_isWidgetType(QObjectH(FObjList.Items[j])) then
begin
Result := QWidgetH(FObjList.Items[j]);
break;
end;
end;
end;
function TQtObjectDump.IsWidget(AnObject: QObjectH): Boolean;
begin
if AnObject <> nil then
Result := QObject_IsWidgetType(AnObject)
else
Result := False;
end;
function TQtObjectDump.GetObjectName(AnObject: QObjectH): WideString;
begin
Result := '';
if AnObject = nil then
exit;
QObject_objectName(AnObject, @Result);
end;
function TQtObjectDump.InheritsQtClass(AnObject: QObjectH;
AQtClass: WideString): Boolean;
begin
if (AnObject = nil) or (AQtClass = '') then
Result := False
else
Result := QObject_inherits(AnObject, @AQtClass);
end;
constructor TQtObjectDump.Create(AnObject: QObjectH);
begin
FRoot := AnObject;
FList := TStringList.Create;
FObjList := TFPList.Create;
end;
destructor TQtObjectDump.Destroy;
begin
FList.Free;
FObjList.Free;
inherited Destroy;
end;
end.

View File

@ -1414,6 +1414,23 @@ type
TQtFileDialog = class(TQtDialog)
private
{$ifndef QT_NATIVE_DIALOGS}
FBackBtn: QWidgetH;
FForwardBtn: QWidgetH;
FUpBtn: QWidgetH;
FFileNameEdit: QWidgetH;
FComboType: QWidgetH;
FComboHistory: QWidgetH;
FSideView: QWidgetH;
FTreeView: QWidgetH;
FListView: QWidgetH;
FTreeViewEventFilter: QObject_hookH;
FListViewEventFilter: QObject_hookH;
FSideViewEventFilter: QObject_hookH;
FFileNameEditEventFilter: QObject_hookH;
FComboTypeEventFilter: QObject_hookH;
FComboHistoryEventFilter: QObject_hookH;
{$endif}
FCurrentChangedHook: QFileDialog_hookH;
FDirecotyEnteredHook: QFileDialog_hookH;
FFilterSelectedHook: QFileDialog_hookH;
@ -1422,6 +1439,9 @@ type
public
procedure AttachEvents; override;
procedure DetachEvents; override;
{$ifndef QT_NATIVE_DIALOGS}
function EventFilter(Sender: QObjectH; Event: QEventH): Boolean; cdecl; override;
{$endif}
procedure CurrentChangedEvent(path: PWideString); cdecl;
procedure FilterSelectedEvent(filter: PWideString); cdecl;
procedure DirectoryEnteredEvent(directory: PWideString); cdecl;
@ -1439,6 +1459,9 @@ type
procedure setReadOnly(const AReadOnly: Boolean);
procedure setSelectedFilter(const ASelFilter: WideString);
procedure setViewMode(const AMode: QFileDialogViewMode);
{$ifndef QT_NATIVE_DIALOGS}
procedure setShortcuts(const AIsOpenDialog: Boolean);
{$endif}
end;
{ TQtMessageBox }
@ -12402,6 +12425,24 @@ end;
function TQtFileDialog.CreateWidget(parent: QWidgetH; f: QtWindowFlags): QWidgetH;
begin
Result := QFileDialog_create(parent, f);
{$ifndef QT_NATIVE_DIALOGS}
FBackBtn := nil;
FForwardBtn := nil;
FUpBtn := nil;
FFileNameEdit := nil;
FComboType := nil;
FComboHistory := nil;
FSideView := nil;;
FTreeView := nil;
FListView := nil;
FTreeViewEventFilter := nil; // detailed view
FListViewEventFilter := nil; // small icons
FSideViewEventFilter := nil; // sidebar
FFileNameEditEventFilter := nil; // filename editor
FComboTypeEventFilter := nil;
FComboHistoryEventFilter := nil;
{$endif}
end;
procedure TQtFileDialog.AttachEvents;
@ -12424,10 +12465,156 @@ begin
QFileDialog_hook_destroy(FCurrentChangedHook);
QFileDialog_hook_destroy(FFilterSelectedHook);
QFileDialog_hook_destroy(FDirecotyEnteredHook);
{$ifndef QT_NATIVE_DIALOGS}
if FTreeViewEventFilter <> nil then
begin
QObject_hook_destroy(FTreeViewEventFilter);
FTreeViewEventFilter := nil;
end;
if FListViewEventFilter <> nil then
begin
QObject_hook_destroy(FListViewEventFilter);
FListViewEventFilter := nil;
end;
if FSideViewEventFilter <> nil then
begin
QObject_hook_destroy(FSideViewEventFilter);
FSideViewEventFilter := nil;
end;
if FFileNameEditEventFilter <> nil then
begin
QObject_hook_destroy(FFileNameEditEventFilter);
FFileNameEditEventFilter := nil;
end;
if FComboTypeEventFilter <> nil then
begin
QObject_hook_destroy(FComboTypeEventFilter);
FComboTypeEventFilter := nil;
end;
if FComboHistoryEventFilter <> nil then
begin
QObject_hook_destroy(FComboHistoryEventFilter);
FComboHistoryEventFilter := nil;
end;
{$endif}
inherited DetachEvents;
end;
{$ifndef QT_NATIVE_DIALOGS}
function TQtFileDialog.EventFilter(Sender: QObjectH; Event: QEventH): Boolean;
cdecl;
begin
Result := False;
if Sender <> Widget then
begin
// TODO: Ctrl + Letter for Open/Save button trigger
// ALT + Left, Up, Right to navigate (Backward, Up parent, Forward) in list.
// ALT + E to focus fileedit
// ALT + H to focus lookInCombo (history combo)
// ALT + L to focus view
// ALT + N to create new folder (TODO)
// ALT + S to select sidebar
// ALT + T to focus file type combo
// ALT + V to change view style (TODO)
case QEvent_type(Event) of
QEventKeyPress:
begin
if (QKeyEvent_modifiers(QKeyEventH(Event)) and QtAltModifier <> 0) then
begin
case QKeyEvent_key(QKeyEventH(Event)) of
QtKey_Left:
begin
if Assigned(FBackBtn) and QWidget_isVisible(FBackBtn) and
QWidget_isEnabled(FBackBtn) then
QAbstractButton_click(QAbstractButtonH(FBackBtn));
Result := True;
end;
QtKey_Right:
begin
if Assigned(FForwardBtn) and QWidget_isVisible(FForwardBtn) and
QWidget_isEnabled(FForwardBtn) then
QAbstractButton_click(QAbstractButtonH(FForwardBtn));
Result := True;
end;
QtKey_Up:
begin
if Assigned(FUpBtn) and QWidget_isVisible(FUpBtn) and
QWidget_isEnabled(FUpBtn) then
QAbstractButton_click(QAbstractButtonH(FUpBtn));
Result := True;
end;
QtKey_E:
begin
if Assigned(FFileNameEdit) and
QWidget_isVisible(FFileNameEdit) and
QWidget_isEnabled(FFileNameEdit) and
not QWidget_hasFocus(FFileNameEdit) then
QWidget_setFocus(FFileNameEdit);
Result := True;
end;
QtKey_H:
begin
if Assigned(FComboHistory) and
QWidget_isVisible(FComboHistory) and
QWidget_isEnabled(FComboHistory) and
not QWidget_hasFocus(FComboHistory) then
QWidget_setFocus(FComboHistory);
Result := True;
end;
QtKey_L:
begin
if Assigned(FTreeView) and
QWidget_isVisible(FTreeView) and
QWidget_isEnabled(FTreeView) and
not QWidget_hasFocus(FTreeView) then
QWidget_setFocus(FTreeView)
else
if Assigned(FListView) and
QWidget_isVisible(FListView) and
QWidget_isEnabled(FListView) and
not QWidget_hasFocus(FListView) then
QWidget_setFocus(FListView);
Result := True;
end;
QtKey_N:
begin
//TODO: create newfolder
Result := True;
end;
QtKey_S:
begin
// select sidebar
if Assigned(FSideView) and
QWidget_isVisible(FSideView) and
QWidget_isEnabled(FSideView) and
not QWidget_hasFocus(FSideView) then
QWidget_setFocus(FSideView);
Result := True;
end;
QtKey_T:
begin
// focus combo filetype
if Assigned(FComboType) and
QWidget_isVisible(FComboType) and
QWidget_isEnabled(FComboType) and
not QWidget_hasFocus(FComboType) then
QWidget_setFocus(FComboType);
Result := True;
end;
QtKey_V:
begin
//TODO: change viewStyle
Result := True;
end;
end;
end;
end;
end;
end else
Result := inherited EventFilter(Sender, Event);
end;
{$endif}
function TQtFileDialog.selectFile: WideString;
begin
QFileDialog_selectFile(QFileDialogH(Widget), @Result);
@ -12503,6 +12690,134 @@ begin
QFileDialog_setViewMode(QFileDialogH(Widget), AMode);
end;
{------------------------------------------------------------------------------
Function: TQtFileDialog.setShortcuts
Params: None
Returns: Nothing
Qt non-native dialogs doesn't set keyboard shortcuts, so we must do that.
This functions hooks eventFilter of all widgets on QFileDialog.
------------------------------------------------------------------------------}
{$ifndef QT_NATIVE_DIALOGS}
procedure TQtFileDialog.setShortcuts(const AIsOpenDialog: Boolean);
var
AnIter: TQtObjectDump;
i: Integer;
Obj: QObjectH;
WStr: WideString;
ToolTip: WideString;
W: QWidgetH;
begin
// if there's auto recognition enabled then don''t set shortcuts
// cause we are maybe native dialog and then boomer.
if not QFileDialog_testOption(QFileDialogH(Widget),
QFileDialogDontUseNativeDialog) then
exit;
FForwardBtn := nil;
FBackBtn := nil;
FUpBtn := nil;
AnIter := TQtObjectDump.Create(Widget);
try
AnIter.DumpObject;
for i := 0 to AnIter.ObjList.Count - 1 do
begin
Obj := QObjectH(AnIter.Objlist.Items[i]);
if AnIter.IsWidget(Obj) then
begin
WStr := AnIter.GetObjectName(Obj);
if (WStr = 'treeView') or (WStr = 'listView') or (WStr = 'sidebar') then
begin
if FForwardBtn = nil then
begin
FForwardBtn := AnIter.FindWidgetByName('forwardButton');
if FForwardBtn <> nil then
begin
ToolTip := 'Forward (Alt + Right)';
QWidget_setToolTip(FForwardBtn, @ToolTip);
end;
end;
if FBackBtn = nil then
begin
FBackBtn := AnIter.FindWidgetByName('backButton');
if FBackBtn <> nil then
begin
ToolTip := 'Back (Alt + Left)';
QWidget_setToolTip(FBackBtn, @ToolTip);
end;
end;
if FUpBtn = nil then
begin
FUpBtn := AnIter.FindWidgetByName('toParentButton');
if FUpBtn <> nil then
begin
ToolTip := 'To parent directory (Alt + Up)';
QWidget_setToolTip(FUpBtn, @ToolTip);
end;
end;
if FForwardBtn <> nil then
begin
if WStr = 'treeView' then
begin
FTreeView := QWidgetH(Obj);
FTreeViewEventFilter := QObject_hook_create(Obj);
QObject_hook_hook_events(FTreeViewEventFilter, @EventFilter);
ToolTip := 'Alt + L to focus this widget';
QWidget_setToolTip(FTreeView, @ToolTip);
end else
if WStr = 'listView' then
begin
FListView := QWidgetH(Obj);
FListViewEventFilter := QObject_hook_create(Obj);
QObject_hook_hook_events(FListViewEventFilter, @EventFilter);
ToolTip := 'Alt + L to focus this widget';
QWidget_setToolTip(FListView, @ToolTip);
end else
if WStr = 'sidebar' then
begin
FSideView := QWidgetH(Obj);
FSideViewEventFilter := QObject_hook_create(Obj);
QObject_hook_hook_events(FSideViewEventFilter, @EventFilter);
ToolTip := 'Alt + S to focus this widget';
QWidget_setToolTip(FSideView, @ToolTip);
end;
end;
end else
if WStr = 'fileNameEdit' then
begin
FFileNameEdit := QWidgetH(Obj);
FFileNameEditEventFilter := QObject_hook_create(Obj);
QObject_hook_hook_events(FFileNameEditEventFilter, @EventFilter);
ToolTip := 'Alt + E to focus this widget';
QWidget_setToolTip(FFileNameEdit, @ToolTip);
end else
if WStr = 'fileTypeCombo' then
begin
FComboType := QWidgetH(Obj);
FComboTypeEventFilter := QObject_hook_create(Obj);
QObject_hook_hook_events(FComboTypeEventFilter, @EventFilter);
ToolTip := 'Alt + T to focus this widget';
QWidget_setToolTip(FComboType, @ToolTip);
end else
if WStr = 'lookInCombo' then
begin
FComboHistory := QWidgetH(Obj);
FComboHistoryEventFilter := QObject_hook_create(Obj);
QObject_hook_hook_events(FComboHistoryEventFilter, @EventFilter);
ToolTip := 'Alt + H to focus this widget';
QWidget_setToolTip(FComboHistory, @ToolTip);
end;
end;
end;
finally
AnIter.Free;
end;
end;
{$endif}
procedure TQtFileDialog.FilterSelectedEvent(filter: PWideString); cdecl;
var
List: TQtStringList;

View File

@ -363,8 +363,12 @@ begin
FileDialog := TFileDialog(ACommonDialog);
QtFileDialog := TQtFileDialog(FileDialog.Handle);
UpdateProperties(FileDialog, QtFileDialog);
{$ifndef QT_NATIVE_DIALOGS}
// set kbd shortcuts in case when we are not native dialog.
QtFileDialog.setShortcuts(FileDialog is TOpenDialog);
{$endif}
{------------------------------------------------------------------------------
Code to call the dialog
@ -410,7 +414,6 @@ begin
FileDialog.UserChoice := mrCancel;
{$else}
QFileDialog_setOption(QFileDialogH(QtFileDialog.Widget),
QFileDialogDontConfirmOverwrite,
not (ofOverwritePrompt in TSaveDialog(FileDialog).Options));