QMenu: Add showTearOffMenu()

The API is incomplete since we can't show a tear-off menu
programatically. This could be useful when restoring the
application state on launch.

Change-Id: Ice1911b44a5b973680f67b0150efacf3d023c2c5
Task-number: QTBUG-47974
Reviewed-by: Friedemann Kleint <Friedemann.Kleint@theqtcompany.com>
Reviewed-by: Shawn Rutledge <shawn.rutledge@theqtcompany.com>
bb10
Gabriel de Dietrich 2016-02-26 17:34:33 -08:00 committed by Shawn Rutledge
parent b5af1bd8cf
commit d19c9cfd29
3 changed files with 85 additions and 16 deletions

View File

@ -1948,7 +1948,7 @@ bool QMenu::isTearOffEnabled() const
contents in a new window. When the menu is in this mode and the menu
is visible returns \c true; otherwise false.
\sa hideTearOffMenu(), isTearOffEnabled()
\sa showTearOffMenu(), hideTearOffMenu(), isTearOffEnabled()
*/
bool QMenu::isTearOffMenuVisible() const
{
@ -1958,15 +1958,54 @@ bool QMenu::isTearOffMenuVisible() const
}
/*!
This function will forcibly hide the torn off menu making it
disappear from the users desktop.
\since 5.7
\sa isTearOffMenuVisible(), isTearOffEnabled()
This function will forcibly show the torn off menu making it
appear on the user's desktop at the specified \e global position \a pos.
\sa hideTearOffMenu(), isTearOffMenuVisible(), isTearOffEnabled()
*/
void QMenu::showTearOffMenu(const QPoint &pos)
{
Q_D(QMenu);
if (!d->tornPopup)
d->tornPopup = new QTornOffMenu(this);
const QSize &s = sizeHint();
d->tornPopup->setGeometry(pos.x(), pos.y(), s.width(), s.height());
d->tornPopup->show();
}
/*!
\overload
\since 5.7
This function will forcibly show the torn off menu making it
appear on the user's desktop under the mouse currsor.
\sa hideTearOffMenu(), isTearOffMenuVisible(), isTearOffEnabled()
*/
void QMenu::showTearOffMenu()
{
showTearOffMenu(QCursor::pos());
}
/*!
This function will forcibly hide the torn off menu making it
disappear from the user's desktop.
\sa showTearOffMenu(), isTearOffMenuVisible(), isTearOffEnabled()
*/
void QMenu::hideTearOffMenu()
{
if (QWidget *w = d_func()->tornPopup)
w->close();
Q_D(QMenu);
if (d->tornPopup) {
d->tornPopup->close();
// QTornOffMenu sets WA_DeleteOnClose, so we
// should consider the torn-off menu deleted.
// This way showTearOffMenu() will not try to
// reuse the dying torn-off menu.
d->tornPopup = Q_NULLPTR;
}
}

View File

@ -171,6 +171,8 @@ public:
bool isTearOffEnabled() const;
bool isTearOffMenuVisible() const;
void showTearOffMenu();
void showTearOffMenu(const QPoint &pos);
void hideTearOffMenu();
void setDefaultAction(QAction *);

View File

@ -591,10 +591,19 @@ void tst_QMenu::widgetActionFocus()
QCOMPARE(m.activeAction(), (QAction *)wa);
}
static QMenu *getTornOffMenu()
{
foreach (QWidget *w, QApplication::allWidgets()) {
if (w->isVisible() && w->inherits("QTornOffMenu"))
return static_cast<QMenu *>(w);
}
return Q_NULLPTR;
}
void tst_QMenu::tearOff()
{
QWidget widget;
QMenu *menu = new QMenu(&widget);
QScopedPointer<QMenu> menu(new QMenu(&widget));
QVERIFY(!menu->isTearOffEnabled()); //default value
menu->setTearOffEnabled(true);
menu->addAction("aaa");
@ -607,24 +616,43 @@ void tst_QMenu::tearOff()
widget.activateWindow();
QVERIFY(QTest::qWaitForWindowActive(&widget));
menu->popup(widget.geometry().topRight() + QPoint(50, 0));
QVERIFY(QTest::qWaitForWindowActive(menu));
QVERIFY(QTest::qWaitForWindowActive(menu.data()));
QVERIFY(!menu->isTearOffMenuVisible());
QTest::mouseClick(menu, Qt::LeftButton, 0, QPoint(3, 3), 10);
QTest::mouseClick(menu.data(), Qt::LeftButton, 0, QPoint(3, 3), 10);
QTRY_VERIFY(menu->isTearOffMenuVisible());
QPointer<QMenu> torn = 0;
foreach (QWidget *w, QApplication::allWidgets()) {
if (w->inherits("QTornOffMenu")) {
torn = static_cast<QMenu *>(w);
break;
}
}
QPointer<QMenu> torn = getTornOffMenu();
QVERIFY(torn);
QVERIFY(torn->isVisible());
menu->hideTearOffMenu();
QVERIFY(!menu->isTearOffMenuVisible());
QVERIFY(!torn->isVisible());
#ifndef QT_NO_CURSOR
// Test under-mouse positioning
menu->showTearOffMenu();
torn = getTornOffMenu();
QVERIFY(torn);
QVERIFY(torn->isVisible());
QVERIFY(menu->isTearOffMenuVisible());
// Some platforms include the window title bar in its geometry.
QTRY_COMPARE(torn->windowHandle()->position(), QCursor::pos());
menu->hideTearOffMenu();
QVERIFY(!menu->isTearOffMenuVisible());
QVERIFY(!torn->isVisible());
// Test custom positioning
const QPoint &pos = QCursor::pos() / 2 + QPoint(10, 10);
menu->showTearOffMenu(pos);
torn = getTornOffMenu();
QVERIFY(torn);
QVERIFY(torn->isVisible());
QVERIFY(menu->isTearOffMenuVisible());
// Some platforms include the window title bar in its geometry.
QTRY_COMPARE(torn->windowHandle()->position(), pos);
#endif // QT_NO_CURSOR
}
void tst_QMenu::layoutDirection()