diff options
author | Richard Moe Gustavsen <richard.gustavsen@theqtcompany.com> | 2015-03-31 13:04:46 +0200 |
---|---|---|
committer | Richard Moe Gustavsen <richard.gustavsen@theqtcompany.com> | 2015-04-04 08:46:42 +0000 |
commit | ce4a759c3dae25b56ec21f98e876b1830c99fa22 (patch) | |
tree | 4c64658f076c61c8016d844690c376d921aef703 /src/plugins/platforms | |
parent | f40cf77b0fa1cd5353ca866a7a5799da9f303081 (diff) |
iOS: enable changing menu items in QIOSMenu while it's showing
If the menu items change while a menu is showing, the current
implementation would crash. The current code tried to take this
scenario into account by using a copy of the item list inside
the native menus, but failed since the list contained pointers
to menu items. And those items would be deleted in a higher layer
when removed from the owning QMenu, even if the native menu was
visible.
One could argue that the list of items should not change while
the menu is visible, but from testing, other platforms handle
this scenario gracefully. So this patch will ensure we do the
same on iOS.
Task-number: QTBUG-44275
Change-Id: I5508e1d6d47039a9aa948c246b33479bd6801868
Reviewed-by: Gabriel de Dietrich <gabriel.dedietrich@theqtcompany.com>
Diffstat (limited to 'src/plugins/platforms')
-rw-r--r-- | src/plugins/platforms/ios/qiosmenu.h | 2 | ||||
-rw-r--r-- | src/plugins/platforms/ios/qiosmenu.mm | 68 |
2 files changed, 51 insertions, 19 deletions
diff --git a/src/plugins/platforms/ios/qiosmenu.h b/src/plugins/platforms/ios/qiosmenu.h index f65a90fb40..15f200bb27 100644 --- a/src/plugins/platforms/ios/qiosmenu.h +++ b/src/plugins/platforms/ios/qiosmenu.h @@ -88,7 +88,7 @@ public: void insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *before) Q_DECL_OVERRIDE; void removeMenuItem(QPlatformMenuItem *menuItem) Q_DECL_OVERRIDE; - void syncMenuItem(QPlatformMenuItem *) Q_DECL_OVERRIDE {} + void syncMenuItem(QPlatformMenuItem *) Q_DECL_OVERRIDE; void syncSeparatorsCollapsible(bool) Q_DECL_OVERRIDE {} void setTag(quintptr tag) Q_DECL_OVERRIDE; diff --git a/src/plugins/platforms/ios/qiosmenu.mm b/src/plugins/platforms/ios/qiosmenu.mm index dfab835579..08fc8a5e9c 100644 --- a/src/plugins/platforms/ios/qiosmenu.mm +++ b/src/plugins/platforms/ios/qiosmenu.mm @@ -60,24 +60,31 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; - (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems { if (self = [super init]) { - m_visibleMenuItems = visibleMenuItems; - NSMutableArray *menuItemArray = [NSMutableArray arrayWithCapacity:m_visibleMenuItems.size()]; - // Create an array of UIMenuItems, one for each visible QIOSMenuItem. Each - // UIMenuItem needs a callback assigned, so we assign one of the placeholder methods - // added to UIWindow (QIOSMenuActionTargets) below. Each method knows its own index, which - // corresponds to the index of the corresponding QIOSMenuItem in m_visibleMenuItems. When - // triggered, menuItemActionCallback will end up being called. - for (int i = 0; i < m_visibleMenuItems.count(); ++i) { - QIOSMenuItem *item = m_visibleMenuItems.at(i); - SEL sel = NSSelectorFromString([NSString stringWithFormat:@"%@%i:", kSelectorPrefix, i]); - [menuItemArray addObject:[[[UIMenuItem alloc] initWithTitle:item->m_text.toNSString() action:sel] autorelease]]; - } - [UIMenuController sharedMenuController].menuItems = menuItemArray; + [self setVisibleMenuItems:visibleMenuItems]; } return self; } +- (void)setVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems +{ + m_visibleMenuItems = visibleMenuItems; + NSMutableArray *menuItemArray = [NSMutableArray arrayWithCapacity:m_visibleMenuItems.size()]; + // Create an array of UIMenuItems, one for each visible QIOSMenuItem. Each + // UIMenuItem needs a callback assigned, so we assign one of the placeholder methods + // added to UIWindow (QIOSMenuActionTargets) below. Each method knows its own index, which + // corresponds to the index of the corresponding QIOSMenuItem in m_visibleMenuItems. When + // triggered, menuItemActionCallback will end up being called. + for (int i = 0; i < m_visibleMenuItems.count(); ++i) { + QIOSMenuItem *item = m_visibleMenuItems.at(i); + SEL sel = NSSelectorFromString([NSString stringWithFormat:@"%@%i:", kSelectorPrefix, i]); + [menuItemArray addObject:[[[UIMenuItem alloc] initWithTitle:item->m_text.toNSString() action:sel] autorelease]]; + } + [UIMenuController sharedMenuController].menuItems = menuItemArray; + if ([UIMenuController sharedMenuController].menuVisible) + [[UIMenuController sharedMenuController] setMenuVisible:YES animated:NO]; +} + - (id)targetForAction:(SEL)action withSender:(id)sender { Q_UNUSED(sender); @@ -122,12 +129,9 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; - (id)initWithVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem { if (self = [super init]) { - self.autoresizingMask = UIViewAutoresizingFlexibleWidth; - m_visibleMenuItems = visibleMenuItems; - m_selectedRow = visibleMenuItems.indexOf(const_cast<QIOSMenuItem *>(selectItem)); - if (m_selectedRow == -1) - m_selectedRow = 0; + [self setVisibleMenuItems:visibleMenuItems selectItem:selectItem]; + self.autoresizingMask = UIViewAutoresizingFlexibleWidth; self.toolbar = [[[UIToolbar alloc] init] autorelease]; self.toolbar.frame.size = [self.toolbar sizeThatFits:self.bounds.size]; self.toolbar.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; @@ -152,6 +156,15 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_"; return self; } +- (void)setVisibleMenuItems:(const QIOSMenuItemList &)visibleMenuItems selectItem:(const QIOSMenuItem *)selectItem +{ + m_visibleMenuItems = visibleMenuItems; + m_selectedRow = visibleMenuItems.indexOf(const_cast<QIOSMenuItem *>(selectItem)); + if (m_selectedRow == -1) + m_selectedRow = 0; + [self reloadAllComponents]; +} + -(void)listenForKeyboardWillHideNotification:(BOOL)listen { if (listen) { @@ -333,11 +346,30 @@ void QIOSMenu::insertMenuItem(QPlatformMenuItem *menuItem, QPlatformMenuItem *be int index = m_menuItems.indexOf(static_cast<QIOSMenuItem *>(before)) + 1; m_menuItems.insert(index, static_cast<QIOSMenuItem *>(menuItem)); } + if (m_currentMenu == this) + syncMenuItem(menuItem); } void QIOSMenu::removeMenuItem(QPlatformMenuItem *menuItem) { m_menuItems.removeOne(static_cast<QIOSMenuItem *>(menuItem)); + if (m_currentMenu == this) + syncMenuItem(menuItem); +} + +void QIOSMenu::syncMenuItem(QPlatformMenuItem *) +{ + if (m_currentMenu != this) + return; + + switch (m_effectiveMenuType) { + case EditMenu: + [m_menuController setVisibleMenuItems:visibleMenuItems()]; + break; + default: + [m_pickerView setVisibleMenuItems:visibleMenuItems() selectItem:m_targetItem]; + break; + } } void QIOSMenu::setTag(quintptr tag) |