Qt: added global actions handling (Alt+Key in app main form).issue #18478

git-svn-id: trunk@29543 -
This commit is contained in:
zeljko 2011-02-14 11:50:23 +00:00
parent 4654e9dfb1
commit 4aa7b988f1
3 changed files with 148 additions and 2 deletions

View File

@ -62,6 +62,8 @@ type
FLastWFPMousePos: TPoint;
FLastWFPResult: HWND;
// global actions
FGlobalActions: TFPList;
FEatNextDeactivate: Boolean;
FOverrideCursor: TObject;
SavedDCList: TFPList;
@ -144,6 +146,13 @@ type
procedure RemoveHandle(AHandle: TObject);
function IsValidHandle(AHandle: HWND): Boolean;
// application global actions (mainform mainmenu mnemonics Alt+XX)
procedure ClearGlobalActions;
procedure AddGlobalAction(AnAction: QActionH);
function ShortcutInGlobalActions(const AMnemonicText: WideString;
out AGlobalActionIndex: Integer): Boolean;
procedure TriggerGlobalAction(const ActionIndex: Integer);
// cache for WindowFromPoint to reduce very expensive calls
// of QApplication_widgetAt() inside WindowFromPoint().
function IsWidgetAtCache(AHandle: HWND): Boolean;

View File

@ -100,6 +100,7 @@ begin
if ((QtVersionMajor = 4) and (QtVersionMinor < 6)) or IsOldKDEInstallation then
QtX11InitializePalettes;
{$ENDIF}
FGlobalActions := TFPList.Create;
end;
{------------------------------------------------------------------------------
@ -140,6 +141,7 @@ begin
SavedHandlesList := nil;
end;
FSocketEventMap.Free;
FGlobalActions.Free;
System.DoneCriticalsection(CriticalSection);
@ -758,6 +760,93 @@ begin
System.LeaveCriticalsection(CriticalSection);
end;
procedure TQtWidgetSet.ClearGlobalActions;
begin
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ClearGlobalActions');
{$ENDIF}
FGlobalActions.Clear;
end;
procedure TQtWidgetSet.AddGlobalAction(AnAction: QActionH);
begin
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.AddGlobalAction() AnAction ',dbgHex(PtrUInt(AnAction)));
{$ENDIF}
FGlobalActions.Add(AnAction);
end;
function TQtWidgetSet.ShortcutInGlobalActions(const AMnemonicText: WideString;
out AGlobalActionIndex: Integer): Boolean;
var
NewKey: QKeySequenceH;
NewStr: WideString;
CurrentKey: QKeySequenceH;
CurrentStr: WideString;
Action: QActionH;
i: Integer;
begin
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ShortcutInGlobalActions ',AMnemonicText);
{$ENDIF}
Result := False;
AGlobalActionIndex := -1;
NewKey := QKeySequence_create();
try
QKeySequence_fromString(NewKey, @AMnemonicText);
NewStr := '';
QKeySequence_toString(NewKey, @NewStr);
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ShortcutInGlobalActions new seq=',NewStr);
{$ENDIF}
for i := 0 to FGlobalActions.Count - 1 do
begin
Action := QActionH(FGlobalActions.Items[i]);
CurrentStr := '';
QAction_text(Action, @CurrentStr);
CurrentKey := QKeySequence_create();
try
QKeySequence_mnemonic(CurrentKey, @CurrentStr);
if not QKeySequence_isEmpty(CurrentKey) then
begin
QKeySequence_toString(CurrentKey, @CurrentStr);
{$IFDEF QT_DEBUG_GLOBALACTIONS}
writeln('TQtWidgetSet.ShortcutInGlobalActions CurrentKey ',
CurrentStr,' NewKey ',NewStr,' Result ? ',CurrentStr = NewStr);
{$ENDIF}
Result := CurrentStr = NewStr;
AGlobalActionIndex := i;
if Result then
break;
end;
finally
QKeySequence_destroy(CurrentKey);
end;
end;
finally
QKeySequence_destroy(NewKey);
end;
end;
procedure TQtWidgetSet.TriggerGlobalAction(const ActionIndex: Integer);
var
Action: QActionH;
MainWin: TQtMainWindow;
begin
Action := QActionH(FGlobalActions[ActionIndex]);
if (Action <> nil) and Assigned(Application.MainForm) and
(Application.MainForm.HandleAllocated) then
begin
MainWin := TQtMainWindow(Application.MainForm.Handle);
MainWin.Activate;
QMenuBar_setActiveAction(QMenuBarH(MainWin.MenuBar.Widget), Action);
// MainWin.MenuBar.;
// QMenu_exec(QAction_menu(Action));
end;
end;
{Params: HWND
This function is needed by cache used in TQtWidgetSet.WindowFromPoint().
Returns: True if we are cached (FLastWFPResult).

View File

@ -1361,6 +1361,7 @@ type
private
FVisible: Boolean;
FHeight: Integer;
FIsApplicationMainMenu: Boolean;
public
constructor Create(const AParent: QWidgetH); overload;
public
@ -2459,6 +2460,8 @@ var
{$ENDIF}
AChar: Char;
AKeyEvent: QKeyEventH;
GlobalAction: Integer;
ActiveWin: QWidgetH;
begin
{$ifdef VerboseQt}
DebugLn('TQtWidget.SlotKey ', dbgsname(LCLObject));
@ -2479,7 +2482,6 @@ begin
Modifiers := QKeyEvent_modifiers(QKeyEventH(Event));
IsSysKey := (QtAltModifier and Modifiers) <> $0;
KeyMsg.KeyData := QtKeyModifiersToKeyState(Modifiers);
{$ifdef windows}
ACharCode := QKeyEvent_nativeVirtualKey(QKeyEventH(Event));
KeyMsg.CharCode := ACharCode;
@ -2491,6 +2493,17 @@ begin
// Loads the UTF-8 character associated with the keypress, if any
QKeyEvent_text(QKeyEventH(Event), @Text);
{we must intercept modifiers for main form menu (if any). issue #18709}
if (Modifiers = QtAltModifier) then
begin
if (QApplication_activeModalWidget() = nil) and
QtWidgetSet.ShortcutInGlobalActions('Alt+'+Text, GlobalAction) then
begin
QtWidgetSet.TriggerGlobalAction(GlobalAction);
exit;
end;
end;
{$note TQtWidget.SlotKey: this is workaround for Qt bug which reports
wrong keys with Shift+Ctrl pressed. Fixes #13450.
LAST REVISION: Qt-4.7.0-8 20101129. zeljko}
@ -4718,7 +4731,10 @@ begin
{$else}
MenuBar := TQtMenuBar.Create(Result);
{$endif}
if not (csDesigning in LCLObject.ComponentState) then
MenuBar.FIsApplicationMainMenu := True;
if (Application.MainForm <> nil) and
(Application.MainForm.FormStyle = fsMDIForm) and
not (csDesigning in LCLObject.ComponentState) then
@ -11105,6 +11121,7 @@ begin
Widget := QMenuBar_create(AParent);
FHeight := getHeight;
FVisible := False;
FIsApplicationMainMenu := False;
setVisible(FVisible);
end;
@ -11121,6 +11138,11 @@ end;
function TQtMenuBar.insertMenu(AIndex: Integer; AMenu: QMenuH): QActionH;
var
actionBefore: QActionH;
Actions: TPtrIntArray;
Action: QActionH;
i: Integer;
seq: QKeySequenceH;
WStr: WideString;
begin
if not FVisible then
begin
@ -11132,6 +11154,32 @@ begin
Result := QMenuBar_insertMenu(QMenuBarH(Widget), actionBefore, AMenu)
else
Result := QMenuBar_addMenu(QMenuBarH(Widget), AMenu);
if FIsApplicationMainMenu then
begin
QWidget_actions(Widget, @Actions);
QtWidgetSet.ClearGlobalActions;
for i := 0 to High(Actions) do
begin
Action := QActionH(Actions[i]);
seq := QKeySequence_create();
QAction_shortcut(Action, seq);
if QKeySequence_isEmpty(seq) then
begin
WStr := '';
QAction_text(Action, @WStr);
QKeySequence_destroy(seq);
seq := nil;
seq := QKeySequence_create();
QKeySequence_mnemonic(seq, @WStr);
if not QKeySequence_isEmpty(seq) then
begin
QAction_setShortcutContext(Action, QtApplicationShortcut);
QtWidgetSet.AddGlobalAction(Action);
end;
end;
QKeySequence_destroy(seq);
end;
end;
end;
function TQtMenuBar.getGeometry: TRect;