+/////////////////////////////////////////////////////////////////////
+// Menu::Impl definition and implementation
+/////////////////////////////////////////////////////////////////////
+
+struct Menu::Impl
+{
+ /// populates the menu or one of its submenu
+ /// This is used as a recursive function
+ void populate(QMenu & qMenu, MenuDefinition const & menu);
+
+ /// Only needed for top level menus.
+ MenuDefinition * top_level_menu;
+ /// our owning view
+ GuiView * view;
+ /// the name of this menu
+ QString name;
+};
+
+
+
+/// Get a MenuDefinition item label from the menu backend
+static QString label(MenuItem const & mi)
+{
+ QString label = mi.label();
+ label.replace("&", "&&");
+
+ QString shortcut = mi.shortcut();
+ if (!shortcut.isEmpty()) {
+ int pos = label.indexOf(shortcut);
+ if (pos != -1)
+ //label.insert(pos, 1, char_type('&'));
+ label.replace(pos, 0, "&");
+ }
+
+ QString const binding = mi.binding();
+ if (!binding.isEmpty())
+ label += '\t' + binding;
+
+ return label;
+}
+
+void Menu::Impl::populate(QMenu & qMenu, MenuDefinition const & menu)
+{
+ LYXERR(Debug::GUI, "populating menu " << menu.name());
+ if (menu.size() == 0) {
+ LYXERR(Debug::GUI, "\tERROR: empty menu " << menu.name());
+ return;
+ }
+ LYXERR(Debug::GUI, " ***** menu entries " << menu.size());
+ MenuDefinition::const_iterator m = menu.begin();
+ MenuDefinition::const_iterator end = menu.end();
+ for (; m != end; ++m) {
+ if (m->kind() == MenuItem::Separator)
+ qMenu.addSeparator();
+ else if (m->kind() == MenuItem::Submenu) {
+ QMenu * subMenu = qMenu.addMenu(label(*m));
+ populate(*subMenu, m->submenu());
+ subMenu->setEnabled(m->status().enabled());
+ } else {
+ // we have a MenuItem::Command
+ qMenu.addAction(new Action(view, QIcon(), label(*m),
+ m->func(), QString(), &qMenu));
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////
+// Menu implementation
+/////////////////////////////////////////////////////////////////////
+
+Menu::Menu(GuiView * gv, QString const & name, bool top_level)
+: QMenu(gv), d(new Menu::Impl)
+{
+ d->top_level_menu = top_level? new MenuDefinition : 0;
+ d->view = gv;
+ d->name = name;
+ setTitle(name);
+ if (d->top_level_menu)
+ connect(this, SIGNAL(aboutToShow()), this, SLOT(updateView()));
+}
+
+
+Menu::~Menu()
+{
+ delete d->top_level_menu;
+ delete d;
+}
+
+
+void Menu::updateView()
+{
+ guiApp->menus().updateMenu(this);
+}
+
+
+/////////////////////////////////////////////////////////////////////
+// Menus::Impl definition and implementation
+/////////////////////////////////////////////////////////////////////
+
+struct Menus::Impl {
+ ///
+ bool hasMenu(QString const &) const;
+ ///
+ MenuDefinition & getMenu(QString const &);
+ ///
+ MenuDefinition const & getMenu(QString const &) const;
+
+ /// Expands some special entries of the menu
+ /** The entries with the following kind are expanded to a
+ sequence of Command MenuItems: Lastfiles, Documents,
+ ViewFormats, ExportFormats, UpdateFormats, Branches, Indices
+ */
+ void expand(MenuDefinition const & frommenu, MenuDefinition & tomenu,
+ BufferView const *) const;
+
+ /// Initialize specific MACOS X menubar
+ void macxMenuBarInit(GuiView * view, QMenuBar * qmb);
+
+ /// Mac special menu.
+ /** This defines a menu whose entries list the FuncRequests
+ that will be removed by expand() in other menus. This is
+ used by the Qt/Mac code.
+
+ NOTE: Qt does not remove the menu items when clearing a QMenuBar,
+ such that the items will keep accessing the FuncRequests in
+ the MenuDefinition. While Menus::Impl might be recreated,
+ we keep mac_special_menu_ in memory by making it static.
+ */
+ static MenuDefinition mac_special_menu_;
+
+ ///
+ MenuList menulist_;
+ ///
+ MenuDefinition menubar_;
+
+ typedef QMap<GuiView *, QHash<QString, Menu*> > NameMap;
+
+ /// name to menu for \c menu() method.
+ NameMap name_map_;
+};
+
+
+MenuDefinition Menus::Impl::mac_special_menu_;
+
+
+/*
+ Here is what the Qt documentation says about how a menubar is chosen:
+
+ 1) If the window has a QMenuBar then it is used. 2) If the window
+ is a modal then its menubar is used. If no menubar is specified
+ then a default menubar is used (as documented below) 3) If the
+ window has no parent then the default menubar is used (as
+ documented below).
+
+ The above 3 steps are applied all the way up the parent window
+ chain until one of the above are satisifed. If all else fails a
+ default menubar will be created, the default menubar on Qt/Mac is
+ an empty menubar, however you can create a different default
+ menubar by creating a parentless QMenuBar, the first one created
+ will thus be designated the default menubar, and will be used
+ whenever a default menubar is needed.
+
+ Thus, for Qt/Mac, we add the menus to a free standing menubar, so
+ that this menubar will be used also when one of LyX' dialogs has
+ focus. (JMarc)
+*/
+void Menus::Impl::macxMenuBarInit(GuiView * view, QMenuBar * qmb)
+{
+ /* Since Qt 4.2, the qt/mac menu code has special code for
+ specifying the role of a menu entry. However, it does not
+ work very well with our scheme of creating menus on demand,
+ and therefore we need to put these entries in a special
+ invisible menu. (JMarc)
+ */
+
+ /* The entries of our special mac menu. If we add support for
+ * special entries in Menus, we could imagine something
+ * like
+ * SpecialItem About " "About LyX" "dialog-show aboutlyx"
+ * and therefore avoid hardcoding. I am not sure it is worth
+ * the hassle, though. (JMarc)
+ */
+ struct MacMenuEntry {
+ FuncCode action;
+ char const * arg;
+ char const * label;
+ QAction::MenuRole role;
+ };
+
+ MacMenuEntry entries[] = {
+ {LFUN_DIALOG_SHOW, "aboutlyx", "About LyX",
+ QAction::AboutRole},
+ {LFUN_DIALOG_SHOW, "prefs", "Preferences",
+ QAction::PreferencesRole},
+ {LFUN_RECONFIGURE, "", "Reconfigure",
+ QAction::ApplicationSpecificRole},
+ {LFUN_LYX_QUIT, "", "Quit LyX", QAction::QuitRole}
+ };
+ const size_t num_entries = sizeof(entries) / sizeof(entries[0]);
+
+ // the special menu for Menus. Fill it up only once.
+ if (mac_special_menu_.size() == 0) {
+ for (size_t i = 0 ; i < num_entries ; ++i) {
+ FuncRequest const func(entries[i].action,
+ from_utf8(entries[i].arg));
+ mac_special_menu_.add(MenuItem(MenuItem::Command,
+ entries[i].label, func));
+ }
+ }
+
+ // add the entries to a QMenu that will eventually be empty
+ // and therefore invisible.
+ QMenu * qMenu = qmb->addMenu("special");
+ MenuDefinition::const_iterator cit = mac_special_menu_.begin();
+ MenuDefinition::const_iterator end = mac_special_menu_.end();
+ for (size_t i = 0 ; cit != end ; ++cit, ++i) {
+ Action * action = new Action(view, QIcon(), cit->label(),
+ cit->func(), QString(), qMenu);
+ action->setMenuRole(entries[i].role);
+ qMenu->addAction(action);
+ }
+}
+
+
+void Menus::Impl::expand(MenuDefinition const & frommenu,
+ MenuDefinition & tomenu, BufferView const * bv) const