Albert
Albert

Reputation: 68360

how to create 'Edit' menu in Qt, esp MacOSX

The 'Edit' menu in MacOSX in most applications is quite intelligent and also simple: It automatically knows whether the current selected widget responds to the related ObjC messages (cut:, copy:, paste:, selectText:) and depending on it, the menu action is greyed out or not. And if you trigger the action, it just sends that ObjC message to the current selected widget. The Cocoa code is basically:

mi = mainMenu.addItemWithTitle_action_keyEquivalent_("Edit", None, "")
m = AppKit.NSMenu.alloc().initWithTitle_("Edit")
mainMenu.setSubmenu_forItem_(m, mi)

m.addItemWithTitle_action_keyEquivalent_('Cut', 'cut:', 'x')
m.addItemWithTitle_action_keyEquivalent_('Copy', 'copy:', 'c')
m.addItemWithTitle_action_keyEquivalent_('Paste', 'paste:', 'v')
m.addItemWithTitle_action_keyEquivalent_('Select all', 'selectText:', 'a')

In addition to that, MacOSX detects that this is an 'Edit'-menu and automatically adds 'Start Dictation...' and Special Characters...' at the end of the menu.

Now I'm developing in Qt and I want to have exactly that behavior (at least in the MacOSX version of my app).

There are already two related questions on SO: here (2011) and here (2010). However, both are somewhat outdated and the solution is far from optimal.

There is the application QtCreator which seems to do it right. However, the solution seems quite complicated. I dived a bit through the code and there is some actionmanager and in the mainwindow setup, it connects it with that:

Context globalContext(Constants::C_GLOBAL);
...
// Select All
icon = QIcon::fromTheme(QLatin1String("edit-select-all"));
tmpaction = new QAction(icon, tr("Select &All"), this);
cmd = am->registerAction(tmpaction, Constants::SELECTALL, globalContext);
cmd->setDefaultKeySequence(QKeySequence::SelectAll);
medit->addAction(cmd, Constants::G_EDIT_SELECTALL);
tmpaction->setEnabled(false);

Then, each relevant widget seems to register itself in that actionmanager, e.g. the texteditor:

m_copyAction      = registerNewAction(QLatin1String(Core::Constants::COPY),      this, SLOT(copyAction()), true);
m_cutAction       = registerNewAction(QLatin1String(Core::Constants::CUT),       this, SLOT(cutAction()), true);
m_pasteAction     = registerNewAction(QLatin1String(Core::Constants::PASTE),     this, SLOT(pasteAction()), true);
m_modifyingActions << m_pasteAction;
m_selectAllAction = registerNewAction(QLatin1String(Core::Constants::SELECTALL), this, SLOT(selectAllAction()), true);

This all seems like so much overkill, esp. when compared to the Cocoa solution.

I wonder whether there is a simpler/cleaner solution, more like the Cocoa code. I thought of creating some proxy object with copy, cut, ... slots which itself tries to dynamically invoke the related methods/slots on the currently selected widget, if they are available. Not sure though if that might cause other problems later.

Also, in my case, my application might not have any window open on MacOSX (in contrast to QtCreator) and that is the main menu, but I guess that is not relevant.

Also, I'm not that used to the user guidelines of other OS'. Does the same behavior makes sense on Windows/Linux? Of course, on those platforms, there is no main menu - the menu would be tight to some window. (QtCreator seems to have the same behavior on each OS.)

Upvotes: 0

Views: 321

Answers (1)

As it stands, Qt provides no mechanism designed to mark a widget as to whether it "can" cut, copy and paste. You need to implement your own. Whatever solution you're after has two aspects.

  1. The API exposed to the rest of the application. The Cocoa API is quite simple. The API exposed within the Creator is reasonably simple too, I think.

  2. The glue code needed to implement that API. This code can be as complex as it needs to be, since you only do it once and then leave it alone.

If the code from creator works for you, then there's no reason (other than licensing) not to use it. Unfortunately, the editable widgets don't offer a common interface for this, so it will require extra work. Such work may belong better within the source code of Qt proper - that's the benefit of having Qt sources.

There's nothing wrong with a simple API and a complex implementation of the same. That's pretty much what Qt is. A simple signal-slot connection mechanism requires a lot of code to properly implement it (as opposed to "textbook" implementations that only work on paper).

Upvotes: 0

Related Questions