+/// Helper for std::find_if
+class MenuNamesEqual
+{
+public:
+ MenuNamesEqual(QString const & name) : name_(name) {}
+ bool operator()(MenuDefinition const & menu) const { return menu.name() == name_; }
+private:
+ QString name_;
+};
+
+
+///
+typedef std::vector<MenuDefinition> MenuList;
+///
+typedef MenuList::const_iterator const_iterator;
+///
+typedef MenuList::iterator iterator;
+
+/////////////////////////////////////////////////////////////////////
+// MenuDefinition implementation
+/////////////////////////////////////////////////////////////////////
+
+void MenuDefinition::addWithStatusCheck(MenuItem const & i)
+{
+ switch (i.kind()) {
+
+ case MenuItem::Command: {
+ FuncStatus status = lyx::getStatus(i.func());
+ if (status.unknown() || (!status.enabled() && i.optional()))
+ break;
+ items_.push_back(i);
+ items_.back().status(status);
+ break;
+ }
+
+ case MenuItem::Submenu: {
+ bool enabled = false;
+ if (i.hasSubmenu()) {
+ for (const_iterator cit = i.submenu().begin();
+ cit != i.submenu().end(); ++cit) {
+ // Only these kind of items affect the status of the submenu
+ if ((cit->kind() == MenuItem::Command
+ || cit->kind() == MenuItem::Submenu
+ || cit->kind() == MenuItem::Help)
+ && cit->status().enabled()) {
+ enabled = true;
+ break;
+ }
+ }
+ }
+ if (enabled || !i.optional()) {
+ items_.push_back(i);
+ items_.back().status().setEnabled(enabled);
+ }
+ break;
+ }
+
+ case MenuItem::Separator:
+ if (!items_.empty() && items_.back().kind() != MenuItem::Separator)
+ items_.push_back(i);
+ break;
+
+ default:
+ items_.push_back(i);
+ }
+}
+
+
+void MenuDefinition::read(Lexer & lex)
+{
+ enum {
+ md_item = 1,
+ md_branches,
+ md_citestyles,
+ md_documents,
+ md_bookmarks,
+ md_charstyles,
+ md_custom,
+ md_elements,
+ md_endmenu,
+ md_exportformats,
+ md_importformats,
+ md_indices,
+ md_indicescontext,
+ md_indiceslists,
+ md_indiceslistscontext,
+ md_lastfiles,
+ md_optitem,
+ md_optsubmenu,
+ md_separator,
+ md_submenu,
+ md_toc,
+ md_updateformats,
+ md_viewformats,
+ md_floatlistinsert,
+ md_floatinsert,
+ md_pasterecent,
+ md_toolbars,
+ md_graphicsgroups,
+ md_spellingsuggestions
+ };
+
+ LexerKeyword menutags[] = {
+ { "bookmarks", md_bookmarks },
+ { "branches", md_branches },
+ { "charstyles", md_charstyles },
+ { "citestyles", md_citestyles },
+ { "custom", md_custom },
+ { "documents", md_documents },
+ { "elements", md_elements },
+ { "end", md_endmenu },
+ { "exportformats", md_exportformats },
+ { "floatinsert", md_floatinsert },
+ { "floatlistinsert", md_floatlistinsert },
+ { "graphicsgroups", md_graphicsgroups },
+ { "importformats", md_importformats },
+ { "indices", md_indices },
+ { "indicescontext", md_indicescontext },
+ { "indiceslists", md_indiceslists },
+ { "indiceslistscontext", md_indiceslistscontext },
+ { "item", md_item },
+ { "lastfiles", md_lastfiles },
+ { "optitem", md_optitem },
+ { "optsubmenu", md_optsubmenu },
+ { "pasterecent", md_pasterecent },
+ { "separator", md_separator },
+ { "spellingsuggestions", md_spellingsuggestions },
+ { "submenu", md_submenu },
+ { "toc", md_toc },
+ { "toolbars", md_toolbars },
+ { "updateformats", md_updateformats },
+ { "viewformats", md_viewformats }
+ };
+
+ lex.pushTable(menutags);
+ lex.setContext("MenuDefinition::read: ");
+
+ bool quit = false;
+ bool optional = false;
+
+ while (lex.isOK() && !quit) {
+ switch (lex.lex()) {
+ case md_optitem:
+ optional = true;
+ // fallback to md_item
+ case md_item: {
+ lex.next(true);
+ docstring const name = translateIfPossible(lex.getDocString());
+ lex.next(true);
+ string const command = lex.getString();
+ FuncRequest func = lyxaction.lookupFunc(command);
+ FuncRequest::Origin origin = FuncRequest::MENU;
+ if (name_.startsWith("context-toc-"))
+ origin = FuncRequest::TOC;
+ add(MenuItem(MenuItem::Command, toqstr(name), func, optional, origin));
+ optional = false;
+ break;
+ }
+
+ case md_separator:
+ add(MenuItem(MenuItem::Separator));
+ break;
+
+ case md_lastfiles:
+ add(MenuItem(MenuItem::Lastfiles));
+ break;
+
+ case md_charstyles:
+ add(MenuItem(MenuItem::CharStyles));
+ break;
+
+ case md_custom:
+ add(MenuItem(MenuItem::Custom));
+ break;
+
+ case md_elements:
+ add(MenuItem(MenuItem::Elements));
+ break;
+
+ case md_documents:
+ add(MenuItem(MenuItem::Documents));
+ break;
+
+ case md_bookmarks:
+ add(MenuItem(MenuItem::Bookmarks));
+ break;
+
+ case md_toc:
+ add(MenuItem(MenuItem::Toc));
+ break;
+
+ case md_viewformats:
+ add(MenuItem(MenuItem::ViewFormats));
+ break;
+
+ case md_updateformats:
+ add(MenuItem(MenuItem::UpdateFormats));
+ break;
+
+ case md_exportformats:
+ add(MenuItem(MenuItem::ExportFormats));
+ break;
+
+ case md_importformats:
+ add(MenuItem(MenuItem::ImportFormats));
+ break;
+
+ case md_floatlistinsert:
+ add(MenuItem(MenuItem::FloatListInsert));
+ break;
+
+ case md_floatinsert:
+ add(MenuItem(MenuItem::FloatInsert));
+ break;
+
+ case md_pasterecent:
+ add(MenuItem(MenuItem::PasteRecent));
+ break;
+
+ case md_toolbars:
+ add(MenuItem(MenuItem::Toolbars));
+ break;
+
+ case md_branches:
+ add(MenuItem(MenuItem::Branches));
+ break;
+
+ case md_citestyles:
+ add(MenuItem(MenuItem::CiteStyles));
+ break;
+
+ case md_graphicsgroups:
+ add(MenuItem(MenuItem::GraphicsGroups));
+ break;
+
+ case md_spellingsuggestions:
+ add(MenuItem(MenuItem::SpellingSuggestions));
+ break;
+
+ case md_indices:
+ add(MenuItem(MenuItem::Indices));
+ break;
+
+ case md_indicescontext:
+ add(MenuItem(MenuItem::IndicesContext));
+ break;
+
+ case md_indiceslists:
+ add(MenuItem(MenuItem::IndicesLists));
+ break;
+
+ case md_indiceslistscontext:
+ add(MenuItem(MenuItem::IndicesListsContext));
+ break;
+
+ case md_optsubmenu:
+ optional = true;
+ // fallback to md_submenu
+ case md_submenu: {
+ lex.next(true);
+ docstring const mlabel = translateIfPossible(lex.getDocString());
+ lex.next(true);
+ docstring const mname = lex.getDocString();
+ add(MenuItem(MenuItem::Submenu,
+ toqstr(mlabel), toqstr(mname), optional));
+ optional = false;
+ break;
+ }
+
+ case md_endmenu:
+ quit = true;
+ break;
+
+ default:
+ lex.printError("Unknown menu tag");
+ break;
+ }
+ }
+ lex.popTable();
+}
+
+
+MenuItem const & MenuDefinition::operator[](size_type i) const
+{
+ return items_[i];
+}
+
+
+bool MenuDefinition::hasFunc(FuncRequest const & func) const
+{
+ for (const_iterator it = begin(), et = end(); it != et; ++it)
+ if (it->func() == func)
+ return true;
+ return false;
+}
+
+
+void MenuDefinition::checkShortcuts() const
+{
+ // This is a quadratic algorithm, but we do not care because
+ // menus are short enough
+ for (const_iterator it1 = begin(); it1 != end(); ++it1) {
+ QString shortcut = it1->shortcut();
+ if (shortcut.isEmpty())
+ continue;
+ if (!it1->label().contains(shortcut))
+ LYXERR0("Menu warning: menu entry \""
+ << it1->label()
+ << "\" does not contain shortcut `"
+ << shortcut << "'.");
+ for (const_iterator it2 = begin(); it2 != it1 ; ++it2) {
+ if (!it2->shortcut().compare(shortcut, Qt::CaseInsensitive)) {
+ LYXERR0("Menu warning: menu entries "
+ << '"' << it1->fulllabel()
+ << "\" and \"" << it2->fulllabel()
+ << "\" share the same shortcut.");
+ }
+ }
+ }
+}
+
+
+bool MenuDefinition::searchMenu(FuncRequest const & func, docstring_list & names) const
+{
+ const_iterator m = begin();
+ const_iterator m_end = end();
+ for (; m != m_end; ++m) {
+ if (m->kind() == MenuItem::Command && m->func() == func) {
+ names.push_back(qstring_to_ucs4(m->label()));
+ return true;
+ }
+ if (m->kind() == MenuItem::Submenu) {
+ names.push_back(qstring_to_ucs4(m->label()));
+ if (!m->hasSubmenu()) {
+ LYXERR(Debug::GUI, "Warning: non existing sub menu label="
+ << m->label() << " name=" << m->submenuname());
+ names.pop_back();
+ continue;
+ }
+ if (m->submenu().searchMenu(func, names))
+ return true;
+ names.pop_back();
+ }
+ }
+ return false;
+}
+
+
+bool compareFormat(Format const * p1, Format const * p2)
+{
+ return *p1 < *p2;
+}
+
+
+QString limitStringLength(docstring const & str)
+{
+ size_t const max_item_length = 45;
+
+ if (str.size() > max_item_length)
+ return toqstr(str.substr(0, max_item_length - 3) + "...");
+
+ return toqstr(str);
+}
+
+
+void MenuDefinition::expandGraphicsGroups(BufferView const * bv)
+{
+ if (!bv)