tdf#128921 tdf#130341 tdf#122053 qt5: Native PopupMenus

This implements native PopupMenus for the qt5 VCL plugin,
which not only gives them the native look and feel, but also
makes context menus faster (tdf#128921), accessible (e.g. to the
Orca screen reader, tdf#122053), and makes them work for a case
in Base's relationship dialog where entries in the non-native context
menu were not selectable/clickable (tdf#130341).

For now, this always shows the popup menu at cursor position, which
can be changed by taking the Rectangle passed to
'Qt5Menu::ShowNativePopupMenu' into account if there should be any
need.

Change-Id: Ie52cbc682acacb92716ff51e8bf7f1ab07d34cf0
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/88512
Tested-by: Jenkins
Reviewed-by: Michael Weghorn <m.weghorn@posteo.de>
This commit is contained in:
Michael Weghorn 2020-02-12 08:07:42 +01:00
parent 8d8f62852a
commit 1e0b16f869
2 changed files with 48 additions and 2 deletions

View file

@ -24,6 +24,17 @@ class QMenuBar;
class Qt5MenuItem;
class Qt5Frame;
/*
* Qt5Menu can represent
* (1) the top-level menu of a menubar, in which case 'mbMenuBar' is true and
* 'mpQMenuBar' refers to the corresponding QMenuBar
* (2) another kind of menu (like a PopupMenu), in which case the corresponding QMenu
* object is instantiated and owned by this Qt5Menu (held in 'mpOwnedQMenu').
* (3) a "submenu" in an existing menu (like (1)), in which case the corresponding
* QMenu object is owned by the corresponding Qt5MenuItem.
*
* For (2) and (3), member 'mpQMenu' points to the corresponding QMenu object.
*/
class Qt5Menu : public QObject, public SalMenu
{
Q_OBJECT
@ -34,6 +45,9 @@ private:
Qt5Frame* mpFrame;
bool mbMenuBar;
QMenuBar* mpQMenuBar;
// self-created QMenu that this Qt5Menu represents, if applicable (s. comment for class)
std::unique_ptr<QMenu> mpOwnedQMenu;
// pointer to QMenu owned by the corresponding Qt5MenuItem or self (-> mpOwnedQMenu)
QMenu* mpQMenu;
QPushButton* mpCloseButton;
QMetaObject::Connection maCloseButtonConnection;
@ -58,6 +72,8 @@ public:
virtual void SetFrame(const SalFrame* pFrame) override;
const Qt5Frame* GetFrame() const;
virtual void ShowMenuBar(bool bVisible) override;
virtual bool ShowNativePopupMenu(FloatingWindow* pWin, const tools::Rectangle& rRect,
FloatWinPopupFlags nFlags) override;
Qt5Menu* GetTopLevel();
virtual void SetItemBits(unsigned nPos, MenuItemBits nBits) override;
virtual void CheckItem(unsigned nPos, bool bCheck) override;

View file

@ -24,6 +24,9 @@
#include <strings.hrc>
#include <bitmaps.hlst>
#include <vcl/floatwin.hxx>
#include <window.h>
Qt5Menu::Qt5Menu(bool bMenuBar)
: mpVCLMenu(nullptr)
, mpParentSalMenu(nullptr)
@ -77,8 +80,15 @@ void Qt5Menu::InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos)
[pSalMenuItem] { slotMenuAboutToHide(pSalMenuItem); });
}
}
else if (mpQMenu)
else
{
if (!mpQMenu)
{
// no QMenu set, instantiate own one
mpOwnedQMenu.reset(new QMenu);
mpQMenu = mpOwnedQMenu.get();
}
if (pSalMenuItem->mpSubMenu)
{
// submenu
@ -148,7 +158,9 @@ void Qt5Menu::InsertMenuItem(Qt5MenuItem* pSalMenuItem, unsigned nPos)
UpdateActionGroupItem(pSalMenuItem);
pAction->setShortcut(toQString(nAccelKey.GetName(GetFrame()->GetWindow())));
const Qt5Frame* pFrame = GetFrame();
if (pFrame)
pAction->setShortcut(toQString(nAccelKey.GetName(pFrame->GetWindow())));
connect(pAction, &QAction::triggered, this,
[pSalMenuItem] { slotMenuTriggered(pSalMenuItem); });
@ -442,6 +454,11 @@ void Qt5Menu::DoFullMenuUpdate(Menu* pMenuBar)
Qt5MenuItem* pSalMenuItem = GetItemAtPos(nItem);
InsertMenuItem(pSalMenuItem, nItem);
SetItemImage(nItem, pSalMenuItem, pSalMenuItem->maImage);
const bool bShowDisabled
= bool(pMenuBar->GetMenuFlags() & MenuFlags::AlwaysShowDisabledEntries)
|| !bool(pMenuBar->GetMenuFlags() & MenuFlags::HideDisabledEntries);
const bool bVisible = bShowDisabled || mpVCLMenu->IsItemEnabled(pSalMenuItem->mnId);
pSalMenuItem->getAction()->setVisible(bVisible);
if (pSalMenuItem->mpSubMenu != nullptr)
{
@ -651,6 +668,19 @@ void Qt5Menu::ShowCloseButton(bool bShow)
pButton->hide();
}
bool Qt5Menu::ShowNativePopupMenu(FloatingWindow*, const tools::Rectangle&,
FloatWinPopupFlags nFlags)
{
assert(mpQMenu);
DoFullMenuUpdate(mpVCLMenu);
mpQMenu->setTearOffEnabled(bool(nFlags & FloatWinPopupFlags::AllowTearOff));
const QPoint aPos = QCursor::pos();
mpQMenu->exec(aPos);
return true;
}
Qt5MenuItem::Qt5MenuItem(const SalItemParams* pItemData)
: mpParentMenu(nullptr)
, mpSubMenu(nullptr)