Cocoa: Reflect menu hierarchy in QCocoaMenu* objects

QCocoaMenu is child of either a QCocoaMenuBar, a QCocoaMenuItem as a
submenu, or nothing as a standalone menu. QCocoaMenuItem is child of
its containing QCocoaMenu.

The parent is set during insertion and cleared during removal.

QMenu needs to be updated to avoid double deletion and leaking its
own platform menu.

Change-Id: Iadf60d8062d7466fa616f84f3761fe322fc9aa2e
Reviewed-by: Morten Johan Sørvig <morten.sorvig@digia.com>
This commit is contained in:
Gabriel de Dietrich 2013-04-24 13:55:00 +02:00 committed by The Qt Project
parent 7a1cdac052
commit 370e89f064
5 changed files with 18 additions and 6 deletions

View File

@ -154,6 +154,7 @@ void QCocoaMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *
QCocoaMenuItem *cocoaItem = static_cast<QCocoaMenuItem *>(menuItem);
QCocoaMenuItem *beforeItem = static_cast<QCocoaMenuItem *>(before);
menuItem->setParent(this);
cocoaItem->sync();
if (beforeItem) {
int index = m_menuItems.indexOf(beforeItem);
@ -209,6 +210,10 @@ void QCocoaMenu::removeMenuItem(QPlatformMenuItem *menuItem)
qWarning() << Q_FUNC_INFO << "Menu does not contain the item to be removed";
return;
}
if (menuItem->parent() == this)
menuItem->setParent(0);
m_menuItems.removeOne(cocoaItem);
if (!cocoaItem->isMerged()) {
if (m_nativeMenu != [cocoaItem->nsItem() menu]) {

View File

@ -109,6 +109,7 @@ void QCocoaMenuBar::insertMenu(QPlatformMenu *platformMenu, QPlatformMenu *befor
[m_nativeMenu addItem: menu->nsMenuItem()];
}
platformMenu->setParent(this);
[m_nativeMenu setSubmenu: menu->nsMenu() forItem: menu->nsMenuItem()];
}
@ -123,6 +124,8 @@ void QCocoaMenuBar::removeMenu(QPlatformMenu *platformMenu)
}
m_menus.removeOne(menu);
if (platformMenu->parent() == this)
platformMenu->setParent(0);
NSUInteger realIndex = [m_nativeMenu indexOfItem:menu->nsMenuItem()];
[m_nativeMenu removeItemAtIndex: realIndex];
}

View File

@ -124,10 +124,13 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
{
if (menu == m_menu)
return;
if (m_menu && m_menu->parent() == this)
m_menu->setParent(0);
QCocoaAutoReleasePool pool;
m_menu = static_cast<QCocoaMenu *>(menu);
if (m_menu) {
m_menu->setParent(this);
} else {
// we previously had a menu, but no longer
// clear out our item so the nexy sync() call builds a new one

View File

@ -154,7 +154,7 @@ void QMenuPrivate::init()
}
platformMenu = QGuiApplicationPrivate::platformTheme()->createPlatformMenu();
if (platformMenu) {
if (!platformMenu.isNull()) {
QObject::connect(platformMenu, SIGNAL(aboutToShow()), q, SIGNAL(aboutToShow()));
QObject::connect(platformMenu, SIGNAL(aboutToHide()), q, SIGNAL(aboutToHide()));
}
@ -2411,7 +2411,7 @@ void QMenu::changeEvent(QEvent *e)
if (d->tornPopup) // torn-off menu
d->tornPopup->setEnabled(isEnabled());
d->menuAction->setEnabled(isEnabled());
if (d->platformMenu)
if (!d->platformMenu.isNull())
d->platformMenu->setEnabled(isEnabled());
}
QWidget::changeEvent(e);
@ -2992,7 +2992,7 @@ void QMenu::actionEvent(QActionEvent *e)
d->widgetItems.remove(e->action());
}
if (d->platformMenu) {
if (!d->platformMenu.isNull()) {
if (e->type() == QEvent::ActionAdded) {
QPlatformMenuItem *menuItem =
QGuiApplicationPrivate::platformTheme()->createPlatformMenuItem();
@ -3201,7 +3201,7 @@ void QMenu::setSeparatorsCollapsible(bool collapse)
d->updateActionRects();
update();
}
if (d->platformMenu)
if (!d->platformMenu.isNull())
d->platformMenu->syncSeparatorsCollapsible(collapse);
}

View File

@ -101,7 +101,8 @@ public:
~QMenuPrivate()
{
delete scroll;
delete platformMenu;
if (!platformMenu.isNull() && !platformMenu->parent())
delete platformMenu.data();
#if defined(Q_OS_WINCE) && !defined(QT_NO_MENUBAR)
delete wce_menu;
#endif
@ -228,7 +229,7 @@ public:
//menu fading/scrolling effects
bool doChildEffects;
QPlatformMenu *platformMenu;
QPointer<QPlatformMenu> platformMenu;
QPointer<QAction> actionAboutToTrigger;