summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/cocoa/qcocoamenuitem.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/cocoa/qcocoamenuitem.mm')
-rw-r--r--src/plugins/platforms/cocoa/qcocoamenuitem.mm194
1 files changed, 110 insertions, 84 deletions
diff --git a/src/plugins/platforms/cocoa/qcocoamenuitem.mm b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
index f8f9648822..e1572e1800 100644
--- a/src/plugins/platforms/cocoa/qcocoamenuitem.mm
+++ b/src/plugins/platforms/cocoa/qcocoamenuitem.mm
@@ -1,5 +1,6 @@
/****************************************************************************
**
+** Copyright (C) 2018 The Qt Company Ltd.
** Copyright (C) 2012 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author James Turner <james.turner@kdab.com>
** Contact: https://www.qt.io/licensing/
**
@@ -41,6 +42,7 @@
#include "qcocoamenuitem.h"
+#include "qcocoansmenu.h"
#include "qcocoamenu.h"
#include "qcocoamenubar.h"
#include "messages.h"
@@ -49,7 +51,6 @@
#include "qcocoaapplication.h" // for custom application category
#include "qcocoamenuloader.h"
#include <QtGui/private/qcoregraphics_p.h>
-#include <QtCore/qregularexpression.h>
#include <QtCore/QDebug>
@@ -92,9 +93,9 @@ NSUInteger keySequenceModifierMask(const QKeySequence &accel)
#endif
QCocoaMenuItem::QCocoaMenuItem() :
- m_native(NULL),
+ m_native(nil),
m_itemView(nil),
- m_menu(NULL),
+ m_menu(nullptr),
m_role(NoRole),
m_iconSize(16),
m_textSynced(false),
@@ -112,9 +113,9 @@ QCocoaMenuItem::~QCocoaMenuItem()
QMacAutoReleasePool pool;
if (m_menu && m_menu->menuParent() == this)
- m_menu->setMenuParent(0);
+ m_menu->setMenuParent(nullptr);
if (m_merged) {
- [m_native setHidden:YES];
+ m_native.hidden = YES;
} else {
if (m_menu && m_menu->attachedItem() == m_native)
m_menu->setAttachedItem(nil);
@@ -140,7 +141,7 @@ void QCocoaMenuItem::setMenu(QPlatformMenu *menu)
return;
if (m_menu && m_menu->menuParent() == this) {
- m_menu->setMenuParent(0);
+ m_menu->setMenuParent(nullptr);
// Free the menu from its parent's influence
m_menu->propagateEnabledState(true);
if (m_native && m_menu->attachedItem() == m_native)
@@ -210,82 +211,75 @@ void QCocoaMenuItem::setNativeContents(WId item)
return;
[m_itemView release];
m_itemView = [itemView retain];
- [m_itemView setAutoresizesSubviews:YES];
- [m_itemView setAutoresizingMask:NSViewWidthSizable];
- [m_itemView setHidden:NO];
- [m_itemView setNeedsDisplay:YES];
+ m_itemView.autoresizesSubviews = YES;
+ m_itemView.autoresizingMask = NSViewWidthSizable;
+ m_itemView.hidden = NO;
+ m_itemView.needsDisplay = YES;
}
NSMenuItem *QCocoaMenuItem::sync()
{
- if (m_isSeparator != [m_native isSeparatorItem]) {
+ if (m_isSeparator != m_native.separatorItem) {
[m_native release];
- if (m_isSeparator) {
- m_native = [[NSMenuItem separatorItem] retain];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- } else
+ if (m_isSeparator)
+ m_native = [[QCocoaNSMenuItem separatorItemWithPlatformMenuItem:this] retain];
+ else
m_native = nil;
}
if ((m_role != NoRole && !m_textSynced) || m_merged) {
- NSMenuItem *mergeItem = nil;
+ QCocoaMenuBar *menubar = nullptr;
+ if (m_role == TextHeuristicRole) {
+ // Recognized menu roles are only found in the first menus below the menubar
+ QObject *p = menuParent();
+ int depth = 1;
+ while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
+ ++depth;
+ QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
+ Q_ASSERT(menuObject);
+ p = menuObject->menuParent();
+ }
+
+ if (menubar && depth < 3)
+ m_detectedRole = detectMenuRole(m_text);
+ else
+ m_detectedRole = NoRole;
+ }
+
QCocoaMenuLoader *loader = [QCocoaMenuLoader sharedMenuLoader];
- switch (m_role) {
- case ApplicationSpecificRole:
- mergeItem = [loader appSpecificMenuItem:reinterpret_cast<NSInteger>(this)];
- break;
+ NSMenuItem *mergeItem = nil;
+ const auto role = effectiveRole();
+ switch (role) {
case AboutRole:
mergeItem = [loader aboutMenuItem];
break;
case AboutQtRole:
mergeItem = [loader aboutQtMenuItem];
break;
+ case PreferencesRole:
+ mergeItem = [loader preferencesMenuItem];
+ break;
+ case ApplicationSpecificRole:
+ mergeItem = [loader appSpecificMenuItem:this];
+ break;
case QuitRole:
mergeItem = [loader quitMenuItem];
break;
- case PreferencesRole:
- mergeItem = [loader preferencesMenuItem];
+ case CutRole:
+ case CopyRole:
+ case PasteRole:
+ case SelectAllRole:
+ if (menubar)
+ mergeItem = menubar->itemForRole(role);
break;
- case TextHeuristicRole: {
- QObject *p = menuParent();
- int depth = 1;
- QCocoaMenuBar *menubar = 0;
- while (depth < 3 && p && !(menubar = qobject_cast<QCocoaMenuBar *>(p))) {
- ++depth;
- QCocoaMenuObject *menuObject = dynamic_cast<QCocoaMenuObject *>(p);
- Q_ASSERT(menuObject);
- p = menuObject->menuParent();
- }
- if (depth == 3 || !menubar)
- break; // Menu item too deep in the hierarchy, or not connected to any menubar
-
- m_detectedRole = detectMenuRole(m_text);
- switch (m_detectedRole) {
- case QPlatformMenuItem::AboutRole:
- if (m_text.indexOf(QRegularExpression(QString::fromLatin1("qt$"),
- QRegularExpression::CaseInsensitiveOption)) == -1)
- mergeItem = [loader aboutMenuItem];
- else
- mergeItem = [loader aboutQtMenuItem];
- break;
- case QPlatformMenuItem::PreferencesRole:
- mergeItem = [loader preferencesMenuItem];
- break;
- case QPlatformMenuItem::QuitRole:
- mergeItem = [loader quitMenuItem];
- break;
- default:
- if (m_detectedRole >= CutRole && m_detectedRole < RoleCount && menubar)
- mergeItem = menubar->itemForRole(m_detectedRole);
- if (!m_text.isEmpty())
- m_textSynced = true;
- break;
- }
+ case NoRole:
+ // The heuristic couldn't resolve the menu role
+ m_textSynced = false;
break;
- }
-
default:
- qWarning() << "Menu item" << m_text << "has unsupported role" << m_role;
+ if (!m_text.isEmpty())
+ m_textSynced = true;
+ break;
}
if (mergeItem) {
@@ -294,7 +288,8 @@ NSMenuItem *QCocoaMenuItem::sync()
[mergeItem retain];
[m_native release];
m_native = mergeItem;
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
+ if (auto *nativeItem = qt_objc_cast<QCocoaNSMenuItem *>(m_native))
+ nativeItem.platformMenuItem = this;
} else if (m_merged) {
// was previously merged, but no longer
[m_native release];
@@ -306,14 +301,14 @@ NSMenuItem *QCocoaMenuItem::sync()
}
if (!m_native) {
- m_native = [[NSMenuItem alloc] initWithTitle:m_text.toNSString()
- action:nil
- keyEquivalent:@""];
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
+ m_native = [[QCocoaNSMenuItem alloc] initWithPlatformMenuItem:this];
+ m_native.title = m_text.toNSString();
}
- [m_native setHidden: !m_isVisible];
- [m_native setView:m_itemView];
+ resolveTargetAction();
+
+ m_native.hidden = !m_isVisible;
+ m_native.view = m_itemView;
QString text = mergeText();
#ifndef QT_NO_SHORTCUT
@@ -331,39 +326,35 @@ NSMenuItem *QCocoaMenuItem::sync()
NSFont *customMenuFont = [NSFont fontWithName:m_font.family().toNSString()
size:m_font.pointSize()];
if (customMenuFont) {
- NSArray *keys = [NSArray arrayWithObjects:NSFontAttributeName, nil];
- NSArray *objects = [NSArray arrayWithObjects:customMenuFont, nil];
- NSDictionary *attributes = [NSDictionary dictionaryWithObjects:objects forKeys:keys];
NSAttributedString *str = [[[NSAttributedString alloc] initWithString:finalString.toNSString()
- attributes:attributes] autorelease];
- [m_native setAttributedTitle: str];
+ attributes:@{NSFontAttributeName: customMenuFont}] autorelease];
+ m_native.attributedTitle = str;
useAttributedTitle = true;
}
}
- if (!useAttributedTitle) {
- [m_native setTitle:finalString.toNSString()];
- }
+ if (!useAttributedTitle)
+ m_native.title = finalString.toNSString();
#ifndef QT_NO_SHORTCUT
if (accel.count() == 1) {
- [m_native setKeyEquivalent:keySequenceToKeyEqivalent(accel)];
- [m_native setKeyEquivalentModifierMask:keySequenceModifierMask(accel)];
+ m_native.keyEquivalent = keySequenceToKeyEqivalent(accel);
+ m_native.keyEquivalentModifierMask = keySequenceModifierMask(accel);
} else
#endif
{
- [m_native setKeyEquivalent:@""];
- [m_native setKeyEquivalentModifierMask:NSCommandKeyMask];
+ m_native.keyEquivalent = @"";
+ m_native.keyEquivalentModifierMask = NSCommandKeyMask;
}
NSImage *img = nil;
if (!m_icon.isNull()) {
img = qt_mac_create_nsimage(m_icon, m_iconSize);
- [img setSize:NSMakeSize(m_iconSize, m_iconSize)];
+ img.size = CGSizeMake(m_iconSize, m_iconSize);
}
- [m_native setImage:img];
+ m_native.image = img;
[img release];
- [m_native setState:m_checked ? NSOnState : NSOffState];
+ m_native.state = m_checked ? NSOnState : NSOffState;
return m_native;
}
@@ -408,8 +399,8 @@ void QCocoaMenuItem::syncMerged()
qWarning("Trying to sync a non-merged item");
return;
}
- [m_native setTag:reinterpret_cast<NSInteger>(this)];
- [m_native setHidden: !m_isVisible];
+
+ m_native.hidden = !m_isVisible;
}
void QCocoaMenuItem::setParentEnabled(bool enabled)
@@ -434,4 +425,39 @@ void QCocoaMenuItem::setIconSize(int size)
m_iconSize = size;
}
+void QCocoaMenuItem::resolveTargetAction()
+{
+ if (m_native.separatorItem)
+ return;
+
+ // Some items created by QCocoaMenuLoader are not
+ // instances of QCocoaNSMenuItem and have their
+ // target/action set as Interface Builder would.
+ if (![m_native isMemberOfClass:[QCocoaNSMenuItem class]])
+ return;
+
+ // Use the responder chain and ensure native modal dialogs
+ // continue receiving cut/copy/paste/etc. key equivalents.
+ SEL roleAction;
+ switch (effectiveRole()) {
+ case CutRole:
+ roleAction = @selector(cut:);
+ break;
+ case CopyRole:
+ roleAction = @selector(copy:);
+ break;
+ case PasteRole:
+ roleAction = @selector(paste:);
+ break;
+ case SelectAllRole:
+ roleAction = @selector(selectAll:);
+ break;
+ default:
+ roleAction = @selector(qt_itemFired:);
+ }
+
+ m_native.action = roleAction;
+ m_native.target = nil;
+}
+
QT_END_NAMESPACE