iOS: don't show popup on call to setVisible

It turns out that setting visibility means whether or not the
menu should appear visible in a parent menu, and not to
actually show or hide the popup. This means that the only way
to show a popup is to call showPopup, which also makes
it simpler since we then always get a parent window as
argument that we can activate and get a focus object from.

Change-Id: Ie3866b5664294f9aa4d694fa422e8116e9c75ced
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@digia.com>
This commit is contained in:
Richard Moe Gustavsen 2014-09-24 13:25:29 +02:00
parent 4dffab4c39
commit ee31bc59be
2 changed files with 72 additions and 96 deletions

View File

@ -126,7 +126,6 @@ private:
quintptr m_tag; quintptr m_tag;
bool m_enabled; bool m_enabled;
bool m_visible; bool m_visible;
bool m_effectiveVisible;
QString m_text; QString m_text;
MenuType m_menuType; MenuType m_menuType;
MenuType m_effectiveMenuType; MenuType m_effectiveMenuType;
@ -140,11 +139,10 @@ private:
static QIOSMenu *m_currentMenu; static QIOSMenu *m_currentMenu;
void updateVisibility(); void updateVisibility();
void updateVisibilityUsingUIMenuController(); void toggleShowUsingUIMenuController(bool show);
void updateVisibilityUsingUIPickerView(); void toggleShowUsingUIPickerView(bool show);
QIOSMenuItemList visibleMenuItems() const; QIOSMenuItemList visibleMenuItems() const;
void repositionMenu(); void repositionMenu();
void hide() { setVisible(false); }
}; };
#endif // QIOSMENU_H #endif // QIOSMENU_H

View File

@ -195,12 +195,12 @@ static NSString *const kSelectorPrefix = @"_qtMenuItem_";
if (!m_visibleMenuItems.isEmpty()) if (!m_visibleMenuItems.isEmpty())
QIOSMenu::currentMenu()->handleItemSelected(m_visibleMenuItems.at(m_selectedRow)); QIOSMenu::currentMenu()->handleItemSelected(m_visibleMenuItems.at(m_selectedRow));
else else
QIOSMenu::currentMenu()->setVisible(false); QIOSMenu::currentMenu()->dismiss();
} }
- (void)cancelMenu - (void)cancelMenu
{ {
QIOSMenu::currentMenu()->setVisible(false); QIOSMenu::currentMenu()->dismiss();
} }
@end @end
@ -299,8 +299,7 @@ QIOSMenu::QIOSMenu()
: QPlatformMenu() : QPlatformMenu()
, m_tag(0) , m_tag(0)
, m_enabled(true) , m_enabled(true)
, m_visible(false) , m_visible(true)
, m_effectiveVisible(false)
, m_text(QString()) , m_text(QString())
, m_menuType(DefaultMenu) , m_menuType(DefaultMenu)
, m_effectiveMenuType(DefaultMenu) , m_effectiveMenuType(DefaultMenu)
@ -348,96 +347,12 @@ void QIOSMenu::setText(const QString &text)
void QIOSMenu::setEnabled(bool enabled) void QIOSMenu::setEnabled(bool enabled)
{ {
if (m_enabled == enabled)
return;
m_enabled = enabled; m_enabled = enabled;
updateVisibility();
}
void QIOSMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
{
m_parentWindow = const_cast<QWindow *>(parentWindow);
m_targetRect = targetRect;
m_targetItem = static_cast<const QIOSMenuItem *>(item);
if (m_parentWindow && !m_parentWindow->isActive())
m_parentWindow->requestActivate();
setVisible(true);
}
void QIOSMenu::handleItemSelected(QIOSMenuItem *menuItem)
{
emit menuItem->activated();
setVisible(false);
if (QIOSMenu *menu = menuItem->m_menu) {
menu->setMenuType(m_effectiveMenuType);
menu->showPopup(m_parentWindow, m_targetRect, 0);
}
}
void QIOSMenu::dismiss()
{
setVisible(false);
} }
void QIOSMenu::setVisible(bool visible) void QIOSMenu::setVisible(bool visible)
{ {
if (m_visible == visible)
return;
m_visible = visible; m_visible = visible;
updateVisibility();
}
void QIOSMenu::updateVisibility()
{
bool visibleAndEnabled = m_visible && m_enabled;
if ((visibleAndEnabled && m_effectiveVisible) || (!visibleAndEnabled && m_currentMenu != this))
return;
if (visibleAndEnabled && !qApp->focusObject()) {
// Since the menus depend on communicating with a focus object, a focus object is required to show
// the menu. Note that QIOSMenu::showPopup() will activate the parent window (and set a focus object)
// before this function is called, so this should normally be the case. Not having a focus object is only
// expected in a hybrid environment where the first responder can be something else than a QUIView (then
// no QWindow will be active). If the focus object changes while the menu is visible, the menu will hide.
qWarning() << "QIOSMenu: cannot open menu without any active QWindows!";
return;
}
m_effectiveVisible = visibleAndEnabled;
if (m_effectiveVisible) {
Q_ASSERT(m_currentMenu != this);
if (m_currentMenu) {
// The current implementation allow only one visible
// menu at a time, so close the one currently showing.
m_currentMenu->setVisible(false);
}
m_currentMenu = this;
m_effectiveMenuType = m_menuType;
connect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QIOSMenu::hide);
} else {
disconnect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QIOSMenu::hide);
m_currentMenu = 0;
}
switch (m_effectiveMenuType) {
case EditMenu:
updateVisibilityUsingUIMenuController();
break;
default:
updateVisibilityUsingUIPickerView();
break;
}
// Emit the signal after the fact in case a
// receiver opens a new menu when receiving it.
emit (m_effectiveVisible ? aboutToShow() : aboutToHide());
} }
void QIOSMenu::setMenuType(QPlatformMenu::MenuType type) void QIOSMenu::setMenuType(QPlatformMenu::MenuType type)
@ -445,9 +360,72 @@ void QIOSMenu::setMenuType(QPlatformMenu::MenuType type)
m_menuType = type; m_menuType = type;
} }
void QIOSMenu::updateVisibilityUsingUIMenuController() void QIOSMenu::handleItemSelected(QIOSMenuItem *menuItem)
{ {
if (m_effectiveVisible) { emit menuItem->activated();
dismiss();
if (QIOSMenu *menu = menuItem->m_menu) {
menu->setMenuType(m_effectiveMenuType);
menu->showPopup(m_parentWindow, m_targetRect, 0);
}
}
void QIOSMenu::showPopup(const QWindow *parentWindow, const QRect &targetRect, const QPlatformMenuItem *item)
{
if (m_currentMenu == this || !m_visible || !m_enabled || !parentWindow)
return;
emit aboutToShow();
m_parentWindow = const_cast<QWindow *>(parentWindow);
m_targetRect = targetRect;
m_targetItem = static_cast<const QIOSMenuItem *>(item);
if (!m_parentWindow->isActive())
m_parentWindow->requestActivate();
if (m_currentMenu && m_currentMenu != this)
m_currentMenu->dismiss();
m_currentMenu = this;
m_effectiveMenuType = m_menuType;
connect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QIOSMenu::dismiss);
switch (m_effectiveMenuType) {
case EditMenu:
toggleShowUsingUIMenuController(true);
break;
default:
toggleShowUsingUIPickerView(true);
break;
}
}
void QIOSMenu::dismiss()
{
if (m_currentMenu != this)
return;
emit aboutToHide();
disconnect(qGuiApp, &QGuiApplication::focusObjectChanged, this, &QIOSMenu::dismiss);
switch (m_effectiveMenuType) {
case EditMenu:
toggleShowUsingUIMenuController(false);
break;
default:
toggleShowUsingUIPickerView(false);
break;
}
m_currentMenu = 0;
}
void QIOSMenu::toggleShowUsingUIMenuController(bool show)
{
if (show) {
Q_ASSERT(!m_menuController); Q_ASSERT(!m_menuController);
m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:visibleMenuItems()]; m_menuController = [[QUIMenuController alloc] initWithVisibleMenuItems:visibleMenuItems()];
repositionMenu(); repositionMenu();
@ -462,11 +440,11 @@ void QIOSMenu::updateVisibilityUsingUIMenuController()
} }
} }
void QIOSMenu::updateVisibilityUsingUIPickerView() void QIOSMenu::toggleShowUsingUIPickerView(bool show)
{ {
static QObject *focusObjectWithPickerView = 0; static QObject *focusObjectWithPickerView = 0;
if (m_effectiveVisible) { if (show) {
Q_ASSERT(!m_pickerView); Q_ASSERT(!m_pickerView);
m_pickerView = [[QUIPickerView alloc] initWithVisibleMenuItems:visibleMenuItems() selectItem:m_targetItem]; m_pickerView = [[QUIPickerView alloc] initWithVisibleMenuItems:visibleMenuItems() selectItem:m_targetItem];