mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-16 04:19:19 +02:00
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:
parent
94c95314be
commit
fd82ff4f5f
@ -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.
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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));
|
||||
|
Loading…
Reference in New Issue
Block a user