Important: Please read the Qt Code of Conduct -

Menu actions and TextHeuristicRole on OS X

  • Qt uses a text-based heuristic on OS X to determine whether an action added to a menu is to be put in one of the special places of the so-called application menu. This works, but can lead to unexpected (and sometimes unpleasant) results because the pattern matching is too broad. A good example is KDE's KDevelop IDE, in which the KDevelop/Preferences menu item will not open KDevelop's configuration (preferences, settings) dialog, but instead launch the configure (or cmake) phase of whatever project is currently selected. This occurs without warning ... and of course the action does not appear at the expected location (Project/Configure Selection).

    I have been trying to implement a workaround in the base KDE libraries, but that workaround isn't perfect and is only possible in KDE4. In KDE 5 (KF5), the KAction and KMenu classes my workaround uses are no longer available, leaving only QAction and QMenu ... which obviously cannot be modified in user code.

    What are my options here? What are the available means of proposing and discussion a patch? I looked at the QAction implementation, and saw that the TextHeuristicRole MenuRole is set without any possibility for an override through for instance a setting that could be changed in KDE's initialisation (or global config) code. Yet this is probably what will be required.

    Are there known cases of Qt applications falling victim to misappropriate menu action "delocalisation"?

  • Lifetime Qt Champion


    Maybe a silly question bug did you try setting the MenuRole property of your QAction to something sensible like PreferencesRole ?

  • Well, that would work, but only the 1st action with that role actually ends up under the Preferences item.
    So you'd probably have to start with creating those "special" actions, and then move on with all the others. On top of that KDE apps often have multiple configure menu actions, with only the last one triggering the application settings dialog.

    And if I wasn't clear enough about it: the goal is not to patch each and every Qt client app that finds its menus reorganised the wrong way...

    In fact, I think that I'd prefer it Qt didn't try to be clever and populate an OS X style Application menu for me. With the possible exception of the Quit action it gives less surprises if you have to scout for a menu item that then triggers the intended action.

    Also remember that the heuristics code does pattern matching, on texts that could be in any language. I think there really ought to be a switch/setting that turns the feature off ...

    BTW, we're talking about this kind of guesstimating:

    case QAction::TextHeuristicRole: {
    QString aboutString = QMenuBar::tr("About").toLower();
    if (t.startsWith(aboutString) || t.endsWith(aboutString)) {
    if (t.indexOf(QRegExp(QString::fromLatin1("qt$"), Qt::CaseInsensitive)) == -1) {
    ret = [loader aboutMenuItem];
    } else {
    ret = [loader aboutQtMenuItem];
    } else if (t.startsWith(QMenuBar::tr("Config").toLower())
    || t.startsWith(QMenuBar::tr("Preference").toLower())
    || t.startsWith(QMenuBar::tr("Options").toLower())
    || t.startsWith(QMenuBar::tr("Setting").toLower())
    || t.startsWith(QMenuBar::tr("Setup").toLower())) {
    ret = [loader preferencesMenuItem];

    (beats me why they use toLower() instead of Qt::CaseInsensitive too, maybe it's slightly faster?)

Log in to reply