@@ -255,34 +255,57 @@ void MainWindow::setController(MainWindowController* new_controller, bool has_fi
255255 createHelpMenu ();
256256
257257#if defined(Q_OS_MACOS)
258- // Defeat Qt's menu text heuristic, as a workaround for QTBUG-30812.
259- // Changing an action's menu role (to QAction::NoRole) after it was
260- // added to the menu is unsupported and triggers crashes (#1077).
261- // Instead, we defeat the heuristic by adding a zero width space at the
262- // beginning and the end of the text of every action in the menus.
263- const auto menubar_actions = menuBar ()->actions ();
264- for (auto action : menubar_actions)
265- {
266- if (const auto menu = action->menu ())
267- {
268- const auto menu_actions = menu->actions ();
269- for (auto action : menu_actions)
270- {
271- static const auto zwsp = QString::fromUtf8 (" \u200B " );
272- action->setText (zwsp + action->text () + zwsp);
273- }
274- }
275- }
276-
277- // Needed to activate the menu bar changes
278258 if (isVisible () && qApp->activeWindow () == this )
279259 {
280260 // Force a menu synchronisation,
281261 // QCocoaMenuBar::updateMenuBarImmediately(),
282262 // via QCocoaNativeInterface::onAppFocusWindowChanged().
263+ // / \todo Review in Qt > 5.6
283264 qApp->focusWindowChanged (qApp->focusWindow ());
284265 }
285- #endif
266+
267+ # if defined(MAPPER_DEVELOPMENT_BUILD)
268+ {
269+ // Qt's menu text heuristic can assign unexpected platform specific roles,
270+ // which resulted in Mapper issue #1067. The only supported solution is
271+ // assigning QAction::NoRole) before adding items to the menubar.
272+ // Cf. QTBUG-30812.
273+ // However, the heuristic is required for some platform-specific items.
274+ // Cf. detectMenuRole() in qtbase/src/plugins/platforms/cocoa/messages.cpp
275+ const auto platform_keywords = {
276+ QCoreApplication::translate (" QCocoaMenuItem" , " Cut" ),
277+ QCoreApplication::translate (" QCocoaMenuItem" , " Copy" ),
278+ QCoreApplication::translate (" QCocoaMenuItem" , " Paste" ),
279+ QCoreApplication::translate (" QCocoaMenuItem" , " Select All" )
280+ };
281+ const auto menubar_actions = menuBar ()->actions ();
282+ for (auto menubar_action : menubar_actions)
283+ {
284+ if (const auto menu = menubar_action->menu ())
285+ {
286+ const auto menu_actions = menu->actions ();
287+ for (auto action : menu_actions)
288+ {
289+ if (action->menuRole () != QAction::TextHeuristicRole
290+ || action->isSeparator ())
291+ continue ;
292+ const auto text = action->text ().remove (QLatin1Char (' &' ));
293+ if (std::none_of (begin (platform_keywords), end (platform_keywords), [&text](const auto & keyword) {
294+ return keyword.compare (text, Qt::CaseInsensitive) == 0 ;
295+ }))
296+ {
297+ // Such warnings may indiciate missing setting of QAction::NoRole
298+ // on a (new) item, or incomplete translations for Mapper or Qt.
299+ qDebug (" Unexpected TextHeuristicRole for \" %s > %s\" " ,
300+ qUtf8Printable (menubar_action->text ()),
301+ qUtf8Printable (action->text ()));
302+ }
303+ }
304+ }
305+ }
306+ }
307+ # endif // MAPPER_DEVELOPMENT_BUILD
308+ #endif // Q_OS_MACOS
286309
287310 setHasAutosaveConflict (false );
288311 setHasUnsavedChanges (false );
@@ -291,18 +314,21 @@ void MainWindow::setController(MainWindowController* new_controller, bool has_fi
291314void MainWindow::createFileMenu ()
292315{
293316 QAction* new_act = new QAction (QIcon (QString::fromLatin1 (" :/images/new.png" )), tr (" &New" ), this );
317+ new_act->setMenuRole (QAction::NoRole);
294318 new_act->setShortcuts (QKeySequence::New);
295319 new_act->setStatusTip (tr (" Create a new map" ));
296320 new_act->setWhatsThis (Util::makeWhatThis (" file_menu.html" ));
297321 connect (new_act, &QAction::triggered, this , &MainWindow::showNewMapWizard);
298322
299323 QAction* open_act = new QAction (QIcon (QString::fromLatin1 (" :/images/open.png" )), tr (" &Open..." ), this );
324+ open_act->setMenuRole (QAction::NoRole);
300325 open_act->setShortcuts (QKeySequence::Open);
301326 open_act->setStatusTip (tr (" Open an existing file" ));
302327 open_act->setWhatsThis (Util::makeWhatThis (" file_menu.html" ));
303328 connect (open_act, &QAction::triggered, this , &MainWindow::showOpenDialog);
304329
305330 open_recent_menu = new QMenu (tr (" Open &recent" ), this );
331+ open_recent_menu->menuAction ()->setMenuRole (QAction::NoRole);
306332 open_recent_menu->setWhatsThis (Util::makeWhatThis (" file_menu.html" ));
307333 for (auto & action : recent_file_act)
308334 {
@@ -314,11 +340,13 @@ void MainWindow::createFileMenu()
314340 // NOTE: if you insert something between open_recent_menu and save_act, adjust updateRecentFileActions()!
315341
316342 save_act = new QAction (QIcon (QString::fromLatin1 (" :/images/save.png" )), tr (" &Save" ), this );
343+ save_act->setMenuRole (QAction::NoRole);
317344 save_act->setShortcuts (QKeySequence::Save);
318345 save_act->setWhatsThis (Util::makeWhatThis (" file_menu.html" ));
319346 connect (save_act, &QAction::triggered, this , &MainWindow::save);
320347
321348 auto save_as_act = new QAction (tr (" Save &as..." ), this );
349+ save_as_act->setMenuRole (QAction::NoRole);
322350 if (QKeySequence::keyBindings (QKeySequence::SaveAs).empty ())
323351 save_as_act->setShortcut (tr (" Ctrl+Shift+S" ));
324352 else
@@ -327,20 +355,21 @@ void MainWindow::createFileMenu()
327355 connect (save_as_act, &QAction::triggered, this , &MainWindow::showSaveAsDialog);
328356
329357 settings_act = new QAction (tr (" Settings..." ), this );
330- settings_act->setShortcut (QKeySequence::Preferences);
331358 settings_act->setMenuRole (QAction::PreferencesRole);
359+ settings_act->setShortcut (QKeySequence::Preferences);
332360 connect (settings_act, &QAction::triggered, this , &MainWindow::showSettings);
333361
334362 close_act = new QAction (QIcon (QString::fromLatin1 (" :/images/close.png" )), tr (" Close" ), this );
363+ close_act->setMenuRole (QAction::NoRole);
335364 close_act->setShortcut (QKeySequence::Close);
336365 close_act->setStatusTip (tr (" Close this file" ));
337366 close_act->setWhatsThis (Util::makeWhatThis (" file_menu.html" ));
338367 connect (close_act, &QAction::triggered, this , &MainWindow::closeFile);
339368
340369 QAction* exit_act = new QAction (tr (" E&xit" ), this );
370+ exit_act->setMenuRole (QAction::QuitRole);
341371 exit_act->setShortcuts (QKeySequence::Quit);
342372 exit_act->setStatusTip (tr (" Exit the application" ));
343- exit_act->setMenuRole (QAction::QuitRole);
344373 exit_act->setWhatsThis (Util::makeWhatThis (" file_menu.html" ));
345374 connect (exit_act, &QAction::triggered, qApp, &QApplication::closeAllWindows);
346375
@@ -381,25 +410,30 @@ void MainWindow::createHelpMenu()
381410{
382411 // Help menu
383412 QAction* manualAct = new QAction (QIcon (QString::fromLatin1 (" :/images/help.png" )), tr (" Open &Manual" ), this );
413+ manualAct->setMenuRole (QAction::NoRole);
384414 manualAct->setStatusTip (tr (" Show the help file for this application" ));
385415 manualAct->setShortcut (QKeySequence::HelpContents);
386416 connect (manualAct, &QAction::triggered, this , &MainWindow::showHelp);
387417
388418 QAction* aboutAct = new QAction (tr (" &About %1" ).arg (appName ()), this );
389- aboutAct->setStatusTip (tr (" Show information about this application" ));
390419 aboutAct->setMenuRole (QAction::AboutRole);
420+ aboutAct->setStatusTip (tr (" Show information about this application" ));
391421 connect (aboutAct, &QAction::triggered, this , &MainWindow::showAbout);
392422
393423 QAction* aboutQtAct = new QAction (tr (" About &Qt" ), this );
394- aboutQtAct->setStatusTip (tr (" Show information about Qt" ));
395424 aboutQtAct->setMenuRole (QAction::AboutQtRole);
425+ aboutQtAct->setStatusTip (tr (" Show information about Qt" ));
396426 connect (aboutQtAct, &QAction::triggered, qApp, QApplication::aboutQt);
397427
398428 if (show_menu)
399429 {
400430 QMenu* helpMenu = menuBar ()->addMenu (tr (" &Help" ));
401431 helpMenu->addAction (manualAct);
402- helpMenu->addAction (QWhatsThis::createAction (this ));
432+ helpMenu->addAction ([this ] {
433+ auto action = QWhatsThis::createAction (this );
434+ action->setMenuRole (QAction::NoRole);
435+ return action;
436+ }());
403437 helpMenu->addSeparator ();
404438 helpMenu->addAction (aboutAct);
405439 helpMenu->addAction (aboutQtAct);
0 commit comments