]> git.lyx.org Git - features.git/blobdiff - src/frontends/qt4/Menus.cpp
Complete the removal of the embedding stuff. Maybe. It's hard to be sure we got every...
[features.git] / src / frontends / qt4 / Menus.cpp
index 84d505b510da5ec11aaa634b2cc9de3952361338..1a91ca82a1c1abb2323166b661c122859be9cc7a 100644 (file)
@@ -5,7 +5,7 @@
  *
  * \author John Levon
  * \author Asger Alstrup
- * \author Lars Gullik Bønnes
+ * \author Lars Gullik Bjønnes
  * \author Jean-Marc Lasgouttes
  * \author André Pönitz
  * \author Dekel Tsur
@@ -45,6 +45,7 @@
 #include "TocBackend.h"
 #include "ToolbarBackend.h"
 
+#include "support/assert.h"
 #include "support/convert.h"
 #include "support/debug.h"
 #include "support/filetools.h"
@@ -53,6 +54,7 @@
 
 #include <QCursor>
 #include <QHash>
+#include <QList>
 #include <QMenuBar>
 #include <QString>
 
@@ -140,7 +142,7 @@ public:
                 bool optional = false)
                : kind_(kind), label_(label), submenuname_(submenu), optional_(optional)
        {
-               BOOST_ASSERT(kind == Submenu);
+               LASSERT(kind == Submenu, /**/);
        }
 
        MenuItem(Kind kind,
@@ -200,9 +202,16 @@ public:
        /// set the description of the  submenu
        void submenuname(QString const & name) { submenuname_ = name; }
        ///
-       MenuDefinition * submenu() const { return submenu_.get(); }
+       bool hasSubmenu() const { return !submenu_.isEmpty(); }
        ///
-       void setSubmenu(MenuDefinition * menu) { submenu_.reset(menu); }
+       MenuDefinition const & submenu() const { return submenu_.at(0); }
+       MenuDefinition & submenu() { return submenu_[0]; }
+       ///
+       void setSubmenu(MenuDefinition const & menu)
+       {
+               submenu_.clear();
+               submenu_.append(menu);
+       }
 
 private:
        ///
@@ -217,8 +226,8 @@ private:
        bool optional_;
        ///
        FuncStatus status_;
-       ///
-       boost::shared_ptr<MenuDefinition> submenu_;
+       /// contains 0 or 1 item.
+       QList<MenuDefinition> submenu_;
 };
 
 ///
@@ -317,10 +326,10 @@ void MenuDefinition::addWithStatusCheck(MenuItem const & i)
        }
 
        case MenuItem::Submenu: {
-               if (i.submenu()) {
+               if (i.hasSubmenu()) {
                        bool enabled = false;
-                       for (const_iterator cit = i.submenu()->begin();
-                            cit != i.submenu()->end(); ++cit) {
+                       for (const_iterator cit = i.submenu().begin();
+                            cit != i.submenu().end(); ++cit) {
                                if ((cit->kind() == MenuItem::Command
                                     || cit->kind() == MenuItem::Submenu)
                                    && cit->status().enabled()) {
@@ -351,7 +360,7 @@ void MenuDefinition::addWithStatusCheck(MenuItem const & i)
 
 void MenuDefinition::read(Lexer & lex)
 {
-       enum Menutags {
+       enum {
                md_item = 1,
                md_branches,
                md_documents,
@@ -373,11 +382,10 @@ void MenuDefinition::read(Lexer & lex)
                md_floatlistinsert,
                md_floatinsert,
                md_pasterecent,
-               md_toolbars,
-               md_last
+               md_toolbars
        };
 
-       struct keyword_item menutags[md_last - 1] = {
+       LexerKeyword menutags[] = {
                { "bookmarks", md_bookmarks },
                { "branches", md_branches },
                { "charstyles", md_charstyles },
@@ -402,9 +410,8 @@ void MenuDefinition::read(Lexer & lex)
                { "viewformats", md_viewformats }
        };
 
-       lex.pushTable(menutags, md_last - 1);
-       if (lyxerr.debugging(Debug::PARSER))
-               lex.printTable(lyxerr);
+       lex.pushTable(menutags);
+       lex.setContext("MenuDefinition::read: ");
 
        bool quit = false;
        bool optional = false;
@@ -512,8 +519,7 @@ void MenuDefinition::read(Lexer & lex)
                        break;
 
                default:
-                       lex.printError("MenuDefinition::read: "
-                                      "Unknown menu tag: `$$Token'");
+                       lex.printError("Unknown menu tag");
                        break;
                }
        }
@@ -573,8 +579,14 @@ bool MenuDefinition::searchMenu(FuncRequest const & func, vector<docstring> & na
                }
                if (m->kind() == MenuItem::Submenu) {
                        names.push_back(qstring_to_ucs4(m->label()));
-                       MenuDefinition const & submenu = *m->submenu();
-                       if (submenu.searchMenu(func, names))
+                       if (!m->hasSubmenu()) {
+                               LYXERR(Debug::GUI, "Warning: non existing sub menu label="
+                                       << fromqstr(m->label())
+                                       << " name=" << fromqstr(m->submenuname()));
+                               names.pop_back();
+                               continue;
+                       }
+                       if (m->submenu().searchMenu(func, names))
                                return true;
                        names.pop_back();
                }
@@ -670,7 +682,7 @@ void MenuDefinition::expandFormats(MenuItem::Kind kind, Buffer const * buf)
 
        typedef vector<Format const *> Formats;
        Formats formats;
-       kb_action action;
+       FuncCode action;
 
        switch (kind) {
        case MenuItem::ImportFormats:
@@ -716,7 +728,7 @@ void MenuDefinition::expandFormats(MenuItem::Kind kind, Buffer const * buf)
                                continue;
                        break;
                default:
-                       BOOST_ASSERT(false);
+                       LASSERT(false, /**/);
                        break;
                }
                // FIXME: if we had proper support for translating the
@@ -829,8 +841,7 @@ void MenuDefinition::expandToc2(Toc const & toc_list,
                size_t pos = from;
                while (pos < to) {
                        size_t new_pos = pos + 1;
-                       while (new_pos < to &&
-                              toc_list[new_pos].depth() > depth)
+                       while (new_pos < to && toc_list[new_pos].depth() > depth)
                                ++new_pos;
 
                        QString label(4 * max(0, toc_list[pos].depth() - depth), ' ');
@@ -844,9 +855,10 @@ void MenuDefinition::expandToc2(Toc const & toc_list,
                                add(MenuItem(MenuItem::Command,
                                                    label, FuncRequest(toc_list[pos].action())));
                        } else {
+                               MenuDefinition sub;
+                               sub.expandToc2(toc_list, pos, new_pos, depth + 1);
                                MenuItem item(MenuItem::Submenu, label);
-                               item.setSubmenu(new MenuDefinition);
-                               item.submenu()->expandToc2(toc_list, pos, new_pos, depth + 1);
+                               item.setSubmenu(sub);
                                add(item);
                        }
                        pos = new_pos;
@@ -881,6 +893,8 @@ void MenuDefinition::expandToc(Buffer const * buf)
                add(MenuItem(MenuItem::Command, qt_("Master Document"), f));
        }
 
+       MenuDefinition other_lists;
+       
        FloatList const & floatlist = buf->params().documentClass().floats();
        TocList const & toc_list = buf->tocBackend().tocs();
        TocList::const_iterator cit = toc_list.begin();
@@ -890,27 +904,29 @@ void MenuDefinition::expandToc(Buffer const * buf)
                if (cit->first == "tableofcontents")
                        continue;
 
-               // All the rest is for floats
-               MenuDefinition * submenu = new MenuDefinition;
-               TocIterator ccit = cit->second.begin();
-               TocIterator eend = cit->second.end();
-               for (; ccit != eend; ++ccit) {
-                       QString const label = limitStringLength(ccit->str());
-                       submenu->add(MenuItem(MenuItem::Command, label,
-                                          FuncRequest(ccit->action())));
-               }
                string const & floatName = floatlist.getType(cit->first).listName();
                QString label;
-               if (!floatName.empty())
+               bool in_other_list = true;
+               if (!floatName.empty()) {
                        label = qt_(floatName);
-               // BUG3633: listings is not a proper float so its name
-               // is not shown in floatlist.
+                       in_other_list = false;
+               }
+               else if (cit->first == "child") {
+                       label = qt_("Child Documents");
+                       in_other_list = false;
+               } else if (cit->first == "graphics")
+                       label = qt_("List of Graphics");
                else if (cit->first == "equation")
                        label = qt_("List of Equations");
                else if (cit->first == "index")
                        label = qt_("List of Indexes");
-               else if (cit->first == "listing")
-                       label = qt_("List of Listings");
+               else if (cit->first == "listing") {
+                       // FIXME: the listing navigate menu causes a crash for unknown
+                       // reason. See http://bugzilla.lyx.org/show_bug.cgi?id=4613
+                       // This is a temporary fix:
+                       //label = qt_("List of Listings");
+                       continue;
+               }
                else if (cit->first == "marginalnote")
                        label = qt_("List of Marginal notes");
                else if (cit->first == "note")
@@ -921,15 +937,41 @@ void MenuDefinition::expandToc(Buffer const * buf)
                        label = qt_("Labels and References");
                else if (cit->first == "citation")
                        label = qt_("List of Citations");
-               // this should not happen now, but if something else like
-               // listings is added later, this can avoid an empty menu name.
                else
-                       label = qt_("Other floats");
+                       // This should not happen unless the entry is missing above.
+                       label = qt_("Other floats: ") + toqstr(cit->first);
+
+               MenuDefinition submenu;
+
+               if (cit->second.size() >= 30) {
+                       FuncRequest f(LFUN_DIALOG_SHOW, "toc " + cit->first);
+                       submenu.add(MenuItem(MenuItem::Command, qt_("Open Navigator..."), f));
+               } else {
+                       TocIterator ccit = cit->second.begin();
+                       TocIterator eend = cit->second.end();
+                       for (; ccit != eend; ++ccit) {
+                               QString const label = limitStringLength(ccit->str());
+                               submenu.add(MenuItem(MenuItem::Command, label,
+                                       FuncRequest(ccit->action())));
+                       }
+               }
+
                MenuItem item(MenuItem::Submenu, label);
                item.setSubmenu(submenu);
+               if (in_other_list)
+                       other_lists.add(item);
+               else {
+                       item.setSubmenu(submenu);
+                       add(item);
+               }
+       }
+       if (!other_lists.empty()) {
+               MenuItem item(MenuItem::Submenu, qt_("Other Lists"));
+               item.setSubmenu(other_lists);
                add(item);
        }
 
+
        // Handle normal TOC
        cit = toc_list.find("tableofcontents");
        if (cit == end) {
@@ -1024,7 +1066,7 @@ struct Menu::Impl
 {
        /// populates the menu or one of its submenu
        /// This is used as a recursive function
-       void populate(QMenu * qMenu, MenuDefinition * menu);
+       void populate(QMenu & qMenu, MenuDefinition const & menu);
 
        /// Only needed for top level menus.
        MenuDefinition * top_level_menu;
@@ -1057,26 +1099,26 @@ static QString label(MenuItem const & mi)
        return label;
 }
 
-void Menu::Impl::populate(QMenu * qMenu, MenuDefinition * menu)
+void Menu::Impl::populate(QMenu & qMenu, MenuDefinition const & menu)
 {
-       LYXERR(Debug::GUI, "populating menu " << fromqstr(menu->name()));
-       if (menu->size() == 0) {
-               LYXERR(Debug::GUI, "\tERROR: empty menu " << fromqstr(menu->name()));
+       LYXERR(Debug::GUI, "populating menu " << fromqstr(menu.name()));
+       if (menu.size() == 0) {
+               LYXERR(Debug::GUI, "\tERROR: empty menu " << fromqstr(menu.name()));
                return;
        }
-       LYXERR(Debug::GUI, " *****  menu entries " << menu->size());
-       MenuDefinition::const_iterator m = menu->begin();
-       MenuDefinition::const_iterator end = menu->end();
+       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();
+                       qMenu.addSeparator();
                else if (m->kind() == MenuItem::Submenu) {
-                       QMenu * subMenu = qMenu->addMenu(label(*m));
-                       populate(subMenu, m->submenu());
+                       QMenu * subMenu = qMenu.addMenu(label(*m));
+                       populate(*subMenu, m->submenu());
                } else {
                        // we have a MenuItem::Command
-                       qMenu->addAction(new Action(*view, QIcon(), label(*m), m->func(),
-                               QString()));
+                       qMenu.addAction(new Action(view, QIcon(), label(*m), 
+                               m->func(), QString(), &qMenu));
                }
        }
 }
@@ -1086,7 +1128,7 @@ void Menu::Impl::populate(QMenu * qMenu, MenuDefinition * menu)
 /////////////////////////////////////////////////////////////////////
 
 Menu::Menu(GuiView * gv, QString const & name, bool top_level)
-: d(new Menu::Impl)
+: QMenu(gv), d(new Menu::Impl)
 {
        d->top_level_menu = top_level? new MenuDefinition : 0;
        d->view = gv;
@@ -1106,9 +1148,10 @@ Menu::~Menu()
 
 void Menu::updateView()
 {
-       guiApp->menus().updateMenu(d->name);
+       guiApp->menus().updateMenu(this);
 }
 
+
 /////////////////////////////////////////////////////////////////////
 // Menus::Impl definition and implementation
 /////////////////////////////////////////////////////////////////////
@@ -1127,10 +1170,10 @@ struct Menus::Impl {
            ViewFormats, ExportFormats, UpdateFormats, Branches
        */
        void expand(MenuDefinition const & frommenu, MenuDefinition & tomenu,
-                   Buffer const *) const;
+               Buffer const *) const;
 
        /// Initialize specific MACOS X menubar
-       void macxMenuBarInit(GuiView * view);
+       void macxMenuBarInit(GuiView * view, QMenuBar * qmb);
 
        /// Mac special menu.
        /** This defines a menu whose entries list the FuncRequests
@@ -1144,7 +1187,7 @@ struct Menus::Impl {
        ///
        MenuDefinition menubar_;
 
-       typedef QHash<QString, Menu *> NameMap;
+       typedef QMap<GuiView *, QHash<QString, Menu*> > NameMap;
 
        /// name to menu for \c menu() method.
        NameMap name_map_;
@@ -1171,14 +1214,8 @@ struct Menus::Impl {
   that this menubar will be used also when one of LyX' dialogs has
   focus. (JMarc)
 */
-void Menus::Impl::macxMenuBarInit(GuiView * view)
+void Menus::Impl::macxMenuBarInit(GuiView * view, QMenuBar * qmb)
 {
-       // The Mac menubar initialisation must be done only once!
-       static bool done = false;
-       if (done)
-               return;
-       done = true;
-
        /* 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,
@@ -1194,7 +1231,7 @@ void Menus::Impl::macxMenuBarInit(GuiView * view)
         * the hassle, though. (JMarc)
         */
        struct MacMenuEntry {
-               kb_action action;
+               FuncCode action;
                char const * arg;
                char const * label;
                QAction::MenuRole role;
@@ -1211,29 +1248,32 @@ void Menus::Impl::macxMenuBarInit(GuiView * view)
        };
        const size_t num_entries = sizeof(entries) / sizeof(entries[0]);
 
-       // the special menu for Menus.
-       for (size_t i = 0 ; i < num_entries ; ++i) {
-               FuncRequest const func(entries[i].action,
-                                      from_utf8(entries[i].arg));
-               specialmenu_.add(MenuItem(MenuItem::Command, entries[i].label, func));
+       // the special menu for Menus. Fill it up only once.
+       if (specialmenu_.size() == 0) {
+               for (size_t i = 0 ; i < num_entries ; ++i) {
+                       FuncRequest const func(entries[i].action,
+                               from_utf8(entries[i].arg));
+                       specialmenu_.add(MenuItem(MenuItem::Command, 
+                               entries[i].label, func));
+               }
        }
-
+       
        // add the entries to a QMenu that will eventually be empty
        // and therefore invisible.
-       QMenu * qMenu = view->menuBar()->addMenu("special");
+       QMenu * qMenu = qmb->addMenu("special");
        MenuDefinition::const_iterator cit = specialmenu_.begin();
        MenuDefinition::const_iterator end = specialmenu_.end();
        for (size_t i = 0 ; cit != end ; ++cit, ++i) {
-               Action * action = new Action(*view, QIcon(), cit->label(),
-                                            cit->func(), QString());
+               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,
-                        Buffer const * buf) const
+void Menus::Impl::expand(MenuDefinition const & frommenu,
+       MenuDefinition & tomenu, Buffer const * buf) const
 {
        if (!tomenu.empty())
                tomenu.clear();
@@ -1298,8 +1338,8 @@ void Menus::Impl::expand(MenuDefinition const & frommenu, MenuDefinition & tomen
 
                case MenuItem::Submenu: {
                        MenuItem item(*cit);
-                       item.setSubmenu(new MenuDefinition(cit->submenuname()));
-                       expand(getMenu(cit->submenuname()), *item.submenu(), buf);
+                       item.setSubmenu(MenuDefinition(cit->submenuname()));
+                       expand(getMenu(cit->submenuname()), item.submenu(), buf);
                        tomenu.addWithStatusCheck(item);
                }
                break;
@@ -1336,7 +1376,7 @@ MenuDefinition const & Menus::Impl::getMenu(QString const & name) const
                MenuNamesEqual(name));
        if (cit == menulist_.end())
                lyxerr << "No submenu named " << fromqstr(name) << endl;
-       BOOST_ASSERT(cit != menulist_.end());
+       LASSERT(cit != menulist_.end(), /**/);
        return (*cit);
 }
 
@@ -1347,41 +1387,44 @@ MenuDefinition & Menus::Impl::getMenu(QString const & name)
                MenuNamesEqual(name));
        if (it == menulist_.end())
                lyxerr << "No submenu named " << fromqstr(name) << endl;
-       BOOST_ASSERT(it != menulist_.end());
+       LASSERT(it != menulist_.end(), /**/);
        return (*it);
 }
 
+
 /////////////////////////////////////////////////////////////////////
-// Menus implementation
+//
+// Menus 
+//
 /////////////////////////////////////////////////////////////////////
 
-Menus::Menus(): d(new Impl) {}
+Menus::Menus() : d(new Impl) {}
 
+Menus::~Menus()
+{
+  delete d;
+}
 
 void Menus::read(Lexer & lex)
 {
-       enum Menutags {
-               md_menu = 1,
+       enum {
+               md_menu,
                md_menubar,
                md_endmenuset,
-               md_last
        };
 
-       struct keyword_item menutags[md_last - 1] = {
+       LexerKeyword menutags[] = {
                { "end", md_endmenuset },
                { "menu", md_menu },
                { "menubar", md_menubar }
        };
 
-       //consistency check
-       if (compare_ascii_no_case(lex.getString(), "menuset")) {
-               lyxerr << "Menubackend::read: ERROR wrong token:`"
-                      << lex.getString() << '\'' << endl;
-       }
+       // consistency check
+       if (compare_ascii_no_case(lex.getString(), "menuset"))
+               LYXERR0("Menus::read: ERROR wrong token: `" << lex.getString() << '\'');
 
-       lex.pushTable(menutags, md_last - 1);
-       if (lyxerr.debugging(Debug::PARSER))
-               lex.printTable(lyxerr);
+       lex.pushTable(menutags);
+       lex.setContext("Menus::read");
 
        bool quit = false;
 
@@ -1406,8 +1449,7 @@ void Menus::read(Lexer & lex)
                        quit = true;
                        break;
                default:
-                       lex.printError("menubackend::read: "
-                                      "Unknown menu tag: `$$Token'");
+                       lex.printError("Unknown menu tag");
                        break;
                }
        }
@@ -1418,19 +1460,23 @@ void Menus::read(Lexer & lex)
 bool Menus::searchMenu(FuncRequest const & func,
        vector<docstring> & names) const
 {
-       return d->menubar_.searchMenu(func, names);
+       MenuDefinition menu;
+       d->expand(d->menubar_, menu, 0);
+       return menu.searchMenu(func, names);
 }
 
 
-void Menus::fillMenuBar(GuiView * view)
+void Menus::fillMenuBar(QMenuBar * qmb, GuiView * view, bool initial)
 {
-       // Clear all menubar contents before filling it.
-       view->menuBar()->clear();
-       
+       if (initial) {
 #ifdef Q_WS_MACX
-       // setup special mac specific menu item
-       d->macxMenuBarInit(view);
+               // setup special mac specific menu item
+               d->macxMenuBarInit(view, qmb);
 #endif
+       } else {
+               // Clear all menubar contents before filling it.
+               qmb->clear();
+       }
 
        LYXERR(Debug::GUI, "populating menu bar" << fromqstr(d->menubar_.name()));
 
@@ -1439,13 +1485,13 @@ void Menus::fillMenuBar(GuiView * view)
                        << fromqstr(d->menubar_.name()));
                return;
        }
-       else {
-               LYXERR(Debug::GUI, "menu bar entries "
-                       << d->menubar_.size());
-       }
+       LYXERR(Debug::GUI, "menu bar entries " << d->menubar_.size());
 
        MenuDefinition menu;
-       d->expand(d->menubar_, menu, view->buffer());
+       Buffer * buf = 0;
+       if (view)
+               buf = view->buffer();
+       d->expand(d->menubar_, menu, buf);
 
        MenuDefinition::const_iterator m = menu.begin();
        MenuDefinition::const_iterator end = menu.end();
@@ -1469,17 +1515,16 @@ void Menus::fillMenuBar(GuiView * view)
 
                Menu * menu = new Menu(view, m->submenuname(), true);
                menu->setTitle(label(*m));
-               view->menuBar()->addMenu(menu);
+               qmb->addMenu(menu);
 
-               d->name_map_[name] = menu;
+               d->name_map_[view][name] = menu;
        }
 }
 
 
-void Menus::updateMenu(QString const & name)
+void Menus::updateMenu(Menu * qmenu)
 {
-       Menu * qmenu = d->name_map_[name];
-       LYXERR(Debug::GUI, "Triggered menu: " << fromqstr(name));
+       LYXERR(Debug::GUI, "Triggered menu: " << fromqstr(qmenu->d->name));
        qmenu->clear();
 
        if (qmenu->d->name.isEmpty())
@@ -1488,30 +1533,33 @@ void Menus::updateMenu(QString const & name)
        // Here, We make sure that theLyXFunc points to the correct LyXView.
        theLyXFunc().setLyXView(qmenu->d->view);
 
-       if (!d->hasMenu(name)) {
+       if (!d->hasMenu(qmenu->d->name)) {
                qmenu->addAction(qt_("No action defined!"));
                LYXERR(Debug::GUI, "\tWARNING: non existing menu: "
                        << fromqstr(qmenu->d->name));
                return;
        }
 
-       MenuDefinition const & fromLyxMenu = d->getMenu(name);
-       d->expand(fromLyxMenu, *qmenu->d->top_level_menu, qmenu->d->view->buffer());
-       qmenu->d->populate(qmenu, qmenu->d->top_level_menu);
+       MenuDefinition const & fromLyxMenu = d->getMenu(qmenu->d->name);
+       Buffer * buf = 0;
+       if (qmenu->d->view)
+               buf = qmenu->d->view->buffer();
+       d->expand(fromLyxMenu, *qmenu->d->top_level_menu, buf);
+       qmenu->d->populate(*qmenu, *qmenu->d->top_level_menu);
 }
 
 
 Menu * Menus::menu(QString const & name, GuiView & view)
 {
        LYXERR(Debug::GUI, "Context menu requested: " << fromqstr(name));
-       Menu * menu = d->name_map_.value(name, 0);
+       Menu * menu = d->name_map_[&view].value(name, 0);
        if (!menu && !name.startsWith("context-")) {
-               LYXERR0("resquested context menu not found: " << fromqstr(name));
+               LYXERR0("requested context menu not found: " << fromqstr(name));
                return 0;
        }
 
        menu = new Menu(&view, name, true);
-       d->name_map_[name] = menu;
+       d->name_map_[&view][name] = menu;
        return menu;
 }