$(ASPELL) $(PSPELL) $(ISPELL) SpellBase.cpp \
Box.cpp \
Box.h \
- MenuBackend.cpp \
- MenuBackend.h \
Dimension.cpp \
Dimension.h \
PrinterParams.cpp \
+++ /dev/null
-/**
- * \file MenuBackend.cpp
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Asger Alstrup
- * \author Lars Gullik Bjønnes
- * \author Jean-Marc Lasgouttes
- * \author André Pönitz
- * \author Dekel Tsur
- * \author Martin Vermeer
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#include <config.h>
-
-#include "MenuBackend.h"
-
-#include "BranchList.h"
-#include "Buffer.h"
-#include "BufferList.h"
-#include "BufferParams.h"
-#include "Converter.h"
-#include "CutAndPaste.h"
-#include "Floating.h"
-#include "FloatList.h"
-#include "Format.h"
-#include "KeyMap.h"
-#include "Session.h"
-#include "LyXAction.h"
-#include "LyX.h" // for lastfiles
-#include "LyXFunc.h"
-#include "Lexer.h"
-#include "Paragraph.h"
-#include "TextClass.h"
-#include "TocBackend.h"
-#include "ToolbarBackend.h"
-
-#include "frontends/Application.h"
-
-#include "support/convert.h"
-#include "support/debug.h"
-#include "support/filetools.h"
-#include "support/gettext.h"
-#include "support/lstrings.h"
-
-#include <boost/bind.hpp>
-
-#include <algorithm>
-#include <ostream>
-
-using namespace std;
-using boost::bind;
-using namespace lyx::support;
-
-namespace lyx {
-
-namespace {
-
-class MenuNamesEqual : public unary_function<Menu, bool> {
-public:
- MenuNamesEqual(docstring const & name)
- : name_(name) {}
- bool operator()(Menu const & menu) const {
- return menu.name() == name_;
- }
-private:
- docstring name_;
-};
-
-} // namespace anon
-
-
-MenuItem::MenuItem(Kind kind)
- : kind_(kind), optional_(false)
-{}
-
-
-MenuItem::MenuItem(Kind kind, docstring const & label,
- docstring const & submenu, bool optional)
- : kind_(kind), label_(label),
- submenuname_(submenu), optional_(optional)
-{
- BOOST_ASSERT(kind == Submenu);
-}
-
-
-MenuItem::MenuItem(Kind kind, docstring const & label,
- FuncRequest const & func, bool optional)
- : kind_(kind), label_(label), func_(func), optional_(optional)
-{
- func_.origin = FuncRequest::MENU;
-}
-
-
-MenuItem::~MenuItem()
-{}
-
-
-void MenuItem::submenu(Menu * menu)
-{
- submenu_.reset(menu);
-}
-
-
-docstring const MenuItem::label() const
-{
- return token(label_, char_type('|'), 0);
-}
-
-
-docstring const MenuItem::shortcut() const
-{
- return token(label_, char_type('|'), 1);
-}
-
-
-docstring const MenuItem::binding() const
-{
- if (kind_ != Command)
- return docstring();
-
- // Get the keys bound to this action, but keep only the
- // first one later
- KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(func_);
-
- if (bindings.size())
- return bindings.begin()->print(KeySequence::ForGui);
-
- LYXERR(Debug::KBMAP, "No binding for "
- << lyxaction.getActionName(func_.action)
- << '(' << to_utf8(func_.argument()) << ')');
- return docstring();
-}
-
-
-Menu & Menu::add(MenuItem const & i)
-{
- items_.push_back(i);
- return *this;
-}
-
-
-Menu & Menu::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: {
- if (i.submenu()) {
- bool enabled = false;
- for (const_iterator cit = i.submenu()->begin();
- cit != i.submenu()->end(); ++cit) {
- if ((cit->kind() == MenuItem::Command
- || cit->kind() == MenuItem::Submenu)
- && cit->status().enabled()) {
- enabled = true;
- break;
- }
- }
- if (enabled || !i.optional()) {
- items_.push_back(i);
- items_.back().status().enabled(enabled);
- }
- }
- else
- items_.push_back(i);
- break;
- }
-
- case MenuItem::Separator:
- if (!items_.empty()
- && items_.back().kind() != MenuItem::Separator)
- items_.push_back(i);
- break;
-
- default:
- items_.push_back(i);
- }
-
- return *this;
-}
-
-
-Menu & Menu::read(Lexer & lex)
-{
- enum Menutags {
- md_item = 1,
- md_branches,
- md_documents,
- md_bookmarks,
- md_charstyles,
- md_custom,
- md_elements,
- md_endmenu,
- md_exportformats,
- md_importformats,
- 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_last
- };
-
- struct keyword_item menutags[md_last - 1] = {
- { "bookmarks", md_bookmarks },
- { "branches", md_branches },
- { "charstyles", md_charstyles },
- { "custom", md_custom },
- { "documents", md_documents },
- { "elements", md_elements },
- { "end", md_endmenu },
- { "exportformats", md_exportformats },
- { "floatinsert", md_floatinsert },
- { "floatlistinsert", md_floatlistinsert },
- { "importformats", md_importformats },
- { "item", md_item },
- { "lastfiles", md_lastfiles },
- { "optitem", md_optitem },
- { "optsubmenu", md_optsubmenu },
- { "pasterecent", md_pasterecent },
- { "separator", md_separator },
- { "submenu", md_submenu },
- { "toc", md_toc },
- { "toolbars", md_toolbars },
- { "updateformats", md_updateformats },
- { "viewformats", md_viewformats }
- };
-
- lex.pushTable(menutags, md_last - 1);
- if (lyxerr.debugging(Debug::PARSER))
- lex.printTable(lyxerr);
-
- 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);
- add(MenuItem(MenuItem::Command, name, func, optional));
- 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_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, mlabel, mname,
- optional));
- optional = false;
- break;
- }
-
- case md_endmenu:
- quit = true;
- break;
-
- default:
- lex.printError("Menu::read: "
- "Unknown menu tag: `$$Token'");
- break;
- }
- }
- lex.popTable();
- return *this;
-}
-
-
-MenuItem const & Menu::operator[](size_type i) const
-{
- return items_[i];
-}
-
-
-bool Menu::hasFunc(FuncRequest const & func) const
-{
- return find_if(begin(), end(),
- bind(equal_to<FuncRequest>(),
- bind(&MenuItem::func, _1),
- func)) != end();
-}
-
-void Menu::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) {
- docstring shortcut = it1->shortcut();
- if (shortcut.empty())
- continue;
- if (!contains(it1->label(), shortcut))
- lyxerr << "Menu warning: menu entry \""
- << to_utf8(it1->label())
- << "\" does not contain shortcut `"
- << to_utf8(shortcut) << "'." << endl;
- for (const_iterator it2 = begin(); it2 != it1 ; ++it2) {
- if (!compare_ascii_no_case(it2->shortcut(), shortcut)) {
- lyxerr << "Menu warning: menu entries "
- << '"' << to_utf8(it1->fulllabel())
- << "\" and \"" << to_utf8(it2->fulllabel())
- << "\" share the same shortcut."
- << endl;
- }
- }
- }
-}
-
-
-bool Menu::searchMenu(FuncRequest const & func, vector<docstring> & 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(m->label());
- return true;
- }
- if (m->kind() == MenuItem::Submenu) {
- names.push_back(m->label());
- Menu submenu = theApp()->menuBackend().getMenu(m->submenuname());
- if (submenu.searchMenu(func, names))
- return true;
- names.pop_back();
- }
- }
- return false;
-}
-
-
-void MenuBackend::specialMenu(Menu const & menu)
-{
- specialmenu_ = menu;
-}
-
-
-namespace {
-
-class compare_format {
-public:
- bool operator()(Format const * p1, Format const * p2) {
- return *p1 < *p2;
- }
-};
-
-docstring const limit_string_length(docstring const & str)
-{
- docstring::size_type const max_item_length = 45;
-
- if (str.size() > max_item_length)
- return str.substr(0, max_item_length - 3) + "...";
- else
- return str;
-}
-
-
-void expandLastfiles(Menu & tomenu)
-{
- lyx::LastFilesSection::LastFiles const & lf = LyX::cref().session().lastFiles().lastFiles();
- lyx::LastFilesSection::LastFiles::const_iterator lfit = lf.begin();
-
- int ii = 1;
-
- for (; lfit != lf.end() && ii < 10; ++lfit, ++ii) {
- string const file = lfit->absFilename();
- docstring const label = convert<docstring>(ii) + ". "
- + makeDisplayPath(file, 30)
- + char_type('|') + convert<docstring>(ii);
- tomenu.add(MenuItem(MenuItem::Command, label, FuncRequest(LFUN_FILE_OPEN, file)));
- }
-}
-
-
-void expandDocuments(Menu & tomenu)
-{
- Buffer * first = theBufferList().first();
- if (first) {
- Buffer * b = first;
- int ii = 1;
-
- // We cannot use a for loop as the buffer list cycles.
- do {
- docstring label = b->fileName().displayName(20);
- if (!b->isClean())
- label = label + "*";
- if (ii < 10)
- label = convert<docstring>(ii) + ". " + label + '|' + convert<docstring>(ii);
- tomenu.add(MenuItem(MenuItem::Command, label,
- FuncRequest(LFUN_BUFFER_SWITCH, b->absFileName())));
-
- b = theBufferList().next(b);
- ++ii;
- } while (b != first);
- } else {
- tomenu.add(MenuItem(MenuItem::Command, _("No Documents Open!"),
- FuncRequest(LFUN_NOACTION)));
- }
-}
-
-
-void expandBookmarks(Menu & tomenu)
-{
- lyx::BookmarksSection const & bm = LyX::cref().session().bookmarks();
-
- for (size_t i = 1; i <= bm.size(); ++i) {
- if (bm.isValid(i)) {
- docstring const label = convert<docstring>(i) + ". "
- + makeDisplayPath(bm.bookmark(i).filename.absFilename(), 20)
- + char_type('|') + convert<docstring>(i);
- tomenu.add(MenuItem(MenuItem::Command, label, FuncRequest(LFUN_BOOKMARK_GOTO,
- convert<docstring>(i))));
- }
- }
-}
-
-
-void expandFormats(MenuItem::Kind kind, Menu & tomenu, Buffer const * buf)
-{
- if (!buf && kind != MenuItem::ImportFormats) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Document Open!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
-
- typedef vector<Format const *> Formats;
- Formats formats;
- kb_action action;
-
- switch (kind) {
- case MenuItem::ImportFormats:
- formats = theConverters().importableFormats();
- action = LFUN_BUFFER_IMPORT;
- break;
- case MenuItem::ViewFormats:
- formats = buf->exportableFormats(true);
- action = LFUN_BUFFER_VIEW;
- break;
- case MenuItem::UpdateFormats:
- formats = buf->exportableFormats(true);
- action = LFUN_BUFFER_UPDATE;
- break;
- default:
- formats = buf->exportableFormats(false);
- action = LFUN_BUFFER_EXPORT;
- }
- sort(formats.begin(), formats.end(), compare_format());
-
- Formats::const_iterator fit = formats.begin();
- Formats::const_iterator end = formats.end();
- for (; fit != end ; ++fit) {
- if ((*fit)->dummy())
- continue;
- docstring label = from_utf8((*fit)->prettyname());
- docstring const shortcut = from_utf8((*fit)->shortcut());
-
- switch (kind) {
- case MenuItem::ImportFormats:
- // FIXME: This is a hack, we should rather solve
- // FIXME: bug 2488 instead.
- if ((*fit)->name() == "text")
- label = _("Plain Text");
- else if ((*fit)->name() == "textparagraph")
- label = _("Plain Text, Join Lines");
- label += "...";
- break;
- case MenuItem::ViewFormats:
- case MenuItem::ExportFormats:
- case MenuItem::UpdateFormats:
- if (!(*fit)->documentFormat())
- continue;
- break;
- default:
- BOOST_ASSERT(false);
- break;
- }
- // FIXME: if we had proper support for translating the
- // format names defined in configure.py, there would
- // not be a need to check whether the shortcut is
- // correct. If we add it uncondiitonally, it would
- // create useless warnings on bad shortcuts
- if (!shortcut.empty() && contains(label, shortcut))
- label += char_type('|') + shortcut;
-
- if (buf)
- tomenu.addWithStatusCheck(MenuItem(MenuItem::Command, label,
- FuncRequest(action, (*fit)->name())));
- else
- tomenu.add(MenuItem(MenuItem::Command, label,
- FuncRequest(action, (*fit)->name())));
- }
-}
-
-
-void expandFloatListInsert(Menu & tomenu, Buffer const * buf)
-{
- if (!buf) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Document Open!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
-
- FloatList const & floats = buf->params().documentClass().floats();
- FloatList::const_iterator cit = floats.begin();
- FloatList::const_iterator end = floats.end();
- for (; cit != end; ++cit) {
- tomenu.addWithStatusCheck(MenuItem(MenuItem::Command,
- _(cit->second.listName()),
- FuncRequest(LFUN_FLOAT_LIST,
- cit->second.type())));
- }
-}
-
-
-void expandFloatInsert(Menu & tomenu, Buffer const * buf)
-{
- if (!buf) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Document Open!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
-
- FloatList const & floats = buf->params().documentClass().floats();
- FloatList::const_iterator cit = floats.begin();
- FloatList::const_iterator end = floats.end();
- for (; cit != end; ++cit) {
- // normal float
- docstring const label = _(cit->second.name());
- tomenu.addWithStatusCheck(MenuItem(MenuItem::Command, label,
- FuncRequest(LFUN_FLOAT_INSERT,
- cit->second.type())));
- }
-}
-
-
-void expandFlexInsert(Menu & tomenu, Buffer const * buf, string s)
-{
- if (!buf) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Document Open!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
- TextClass::InsetLayouts const & insetLayouts =
- buf->params().documentClass().insetLayouts();
- TextClass::InsetLayouts::const_iterator cit = insetLayouts.begin();
- TextClass::InsetLayouts::const_iterator end = insetLayouts.end();
- for (; cit != end; ++cit) {
- docstring const label = cit->first;
- if (cit->second.lyxtype() == s)
- tomenu.addWithStatusCheck(MenuItem(MenuItem::Command,
- label, FuncRequest(LFUN_FLEX_INSERT,
- label)));
- }
-}
-
-
-Menu::size_type const max_number_of_items = 25;
-
-void expandToc2(Menu & tomenu,
- Toc const & toc_list,
- Toc::size_type from,
- Toc::size_type to, int depth)
-{
- int shortcut_count = 0;
-
- // check whether depth is smaller than the smallest depth in toc.
- int min_depth = 1000;
- for (Toc::size_type i = from; i < to; ++i)
- min_depth = min(min_depth, toc_list[i].depth());
- if (min_depth > depth)
- depth = min_depth;
-
-
- if (to - from <= max_number_of_items) {
- for (Toc::size_type i = from; i < to; ++i) {
- docstring label(4 * max(0, toc_list[i].depth() - depth), char_type(' '));
- label += limit_string_length(toc_list[i].str());
- if (toc_list[i].depth() == depth
- && shortcut_count < 9) {
- if (label.find(convert<docstring>(shortcut_count + 1)) != docstring::npos)
- label += char_type('|') + convert<docstring>(++shortcut_count);
- }
- tomenu.add(MenuItem(MenuItem::Command, label,
- FuncRequest(toc_list[i].action())));
- }
- } else {
- Toc::size_type pos = from;
- while (pos < to) {
- Toc::size_type new_pos = pos + 1;
- while (new_pos < to &&
- toc_list[new_pos].depth() > depth)
- ++new_pos;
-
- docstring label(4 * max(0, toc_list[pos].depth() - depth), ' ');
- label += limit_string_length(toc_list[pos].str());
- if (toc_list[pos].depth() == depth &&
- shortcut_count < 9) {
- if (label.find(convert<docstring>(shortcut_count + 1)) != docstring::npos)
- label += char_type('|') + convert<docstring>(++shortcut_count);
- }
- if (new_pos == pos + 1) {
- tomenu.add(MenuItem(MenuItem::Command,
- label, FuncRequest(toc_list[pos].action())));
- } else {
- MenuItem item(MenuItem::Submenu, label);
- item.submenu(new Menu);
- expandToc2(*item.submenu(),
- toc_list, pos, new_pos, depth + 1);
- tomenu.add(item);
- }
- pos = new_pos;
- }
- }
-}
-
-
-void expandToc(Menu & tomenu, Buffer const * buf)
-{
- // To make things very cleanly, we would have to pass buf to
- // all MenuItem constructors and to expandToc2. However, we
- // know that all the entries in a TOC will be have status_ ==
- // OK, so we avoid this unnecessary overhead (JMarc)
-
- if (!buf) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Document Open!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
-
- Buffer* cbuf = const_cast<Buffer*>(buf);
- cbuf->tocBackend().update();
- cbuf->structureChanged();
-
- // Add an entry for the master doc if this is a child doc
- Buffer const * const master = buf->masterBuffer();
- if (buf != master) {
- ParIterator const pit = par_iterator_begin(master->inset());
- string const arg = convert<string>(pit->id());
- FuncRequest f(LFUN_PARAGRAPH_GOTO, arg);
- tomenu.add(MenuItem(MenuItem::Command, _("Master Document"), f));
- }
-
- FloatList const & floatlist = buf->params().documentClass().floats();
- TocList const & toc_list = buf->tocBackend().tocs();
- TocList::const_iterator cit = toc_list.begin();
- TocList::const_iterator end = toc_list.end();
- for (; cit != end; ++cit) {
- // Handle this later
- if (cit->first == "tableofcontents")
- continue;
-
- // All the rest is for floats
- auto_ptr<Menu> menu(new Menu);
- TocIterator ccit = cit->second.begin();
- TocIterator eend = cit->second.end();
- for (; ccit != eend; ++ccit) {
- docstring const label = limit_string_length(ccit->str());
- menu->add(MenuItem(MenuItem::Command,
- label,
- FuncRequest(ccit->action())));
- }
- string const & floatName = floatlist.getType(cit->first).listName();
- docstring label;
- if (!floatName.empty())
- label = _(floatName);
- // BUG3633: listings is not a proper float so its name
- // is not shown in floatlist.
- else if (cit->first == "equation")
- label = _("List of Equations");
- else if (cit->first == "index")
- label = _("List of Indexes");
- else if (cit->first == "listing")
- label = _("List of Listings");
- else if (cit->first == "marginalnote")
- label = _("List of Marginal notes");
- else if (cit->first == "note")
- label = _("List of Notes");
- else if (cit->first == "footnote")
- label = _("List of Foot notes");
- else if (cit->first == "label")
- label = _("Labels and References");
- else if (cit->first == "citation")
- label = _("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 = _("Other floats");
- MenuItem item(MenuItem::Submenu, label);
- item.submenu(menu.release());
- tomenu.add(item);
- }
-
- // Handle normal TOC
- cit = toc_list.find("tableofcontents");
- if (cit == end) {
- tomenu.addWithStatusCheck(MenuItem(MenuItem::Command,
- _("No Table of contents"),
- FuncRequest()));
- } else {
- expandToc2(tomenu, cit->second, 0, cit->second.size(), 0);
- }
-}
-
-
-void expandPasteRecent(Menu & tomenu)
-{
- vector<docstring> const sel = cap::availableSelections();
-
- vector<docstring>::const_iterator cit = sel.begin();
- vector<docstring>::const_iterator end = sel.end();
-
- for (unsigned int index = 0; cit != end; ++cit, ++index) {
- tomenu.add(MenuItem(MenuItem::Command, *cit,
- FuncRequest(LFUN_PASTE, convert<string>(index))));
- }
-}
-
-
-void expandToolbars(Menu & tomenu)
-{
- //
- // extracts the toolbars from the backend
- ToolbarBackend::Toolbars::const_iterator cit = toolbarbackend.begin();
- ToolbarBackend::Toolbars::const_iterator end = toolbarbackend.end();
-
- for (; cit != end; ++cit) {
- docstring label = _(cit->gui_name);
- // frontends are not supposed to turn on/off toolbars,
- // if they cannot update ToolbarBackend::flags. That
- // is to say, ToolbarsBackend::flags should reflect
- // the true state of toolbars.
- //
- // menu is displayed as
- // on/off review
- // and
- // review (auto)
- // in the case of auto.
- if (cit->flags & ToolbarInfo::AUTO)
- label += _(" (auto)");
- tomenu.add(MenuItem(MenuItem::Command, label,
- FuncRequest(LFUN_TOOLBAR_TOGGLE, cit->name + " allowauto")));
- }
-}
-
-
-void expandBranches(Menu & tomenu, Buffer const * buf)
-{
- if (!buf) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Document Open!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
-
- BufferParams const & params = buf->masterBuffer()->params();
- if (params.branchlist().empty()) {
- tomenu.add(MenuItem(MenuItem::Command,
- _("No Branch in Document!"),
- FuncRequest(LFUN_NOACTION)));
- return;
- }
-
- BranchList::const_iterator cit = params.branchlist().begin();
- BranchList::const_iterator end = params.branchlist().end();
-
- for (int ii = 1; cit != end; ++cit, ++ii) {
- docstring label = cit->getBranch();
- if (ii < 10)
- label = convert<docstring>(ii) + ". " + label + char_type('|') + convert<docstring>(ii);
- tomenu.addWithStatusCheck(MenuItem(MenuItem::Command, label,
- FuncRequest(LFUN_BRANCH_INSERT,
- cit->getBranch())));
- }
-}
-
-
-} // namespace anon
-
-
-void MenuBackend::expand(Menu const & frommenu, Menu & tomenu,
- Buffer const * buf) const
-{
- if (!tomenu.empty())
- tomenu.clear();
-
- for (Menu::const_iterator cit = frommenu.begin();
- cit != frommenu.end() ; ++cit) {
- switch (cit->kind()) {
- case MenuItem::Lastfiles:
- expandLastfiles(tomenu);
- break;
-
- case MenuItem::Documents:
- expandDocuments(tomenu);
- break;
-
- case MenuItem::Bookmarks:
- expandBookmarks(tomenu);
- break;
-
- case MenuItem::ImportFormats:
- case MenuItem::ViewFormats:
- case MenuItem::UpdateFormats:
- case MenuItem::ExportFormats:
- expandFormats(cit->kind(), tomenu, buf);
- break;
-
- case MenuItem::CharStyles:
- expandFlexInsert(tomenu, buf, "charstyle");
- break;
-
- case MenuItem::Custom:
- expandFlexInsert(tomenu, buf, "custom");
- break;
-
- case MenuItem::Elements:
- expandFlexInsert(tomenu, buf, "element");
- break;
-
- case MenuItem::FloatListInsert:
- expandFloatListInsert(tomenu, buf);
- break;
-
- case MenuItem::FloatInsert:
- expandFloatInsert(tomenu, buf);
- break;
-
- case MenuItem::PasteRecent:
- expandPasteRecent(tomenu);
- break;
-
- case MenuItem::Toolbars:
- expandToolbars(tomenu);
- break;
-
- case MenuItem::Branches:
- expandBranches(tomenu, buf);
- break;
-
- case MenuItem::Toc:
- expandToc(tomenu, buf);
- break;
-
- case MenuItem::Submenu: {
- MenuItem item(*cit);
- item.submenu(new Menu(cit->submenuname()));
- expand(getMenu(cit->submenuname()),
- *item.submenu(), buf);
- tomenu.addWithStatusCheck(item);
- }
- break;
-
- case MenuItem::Separator:
- tomenu.addWithStatusCheck(*cit);
- break;
-
- case MenuItem::Command:
- if (!specialmenu_.hasFunc(cit->func()))
- tomenu.addWithStatusCheck(*cit);
- }
- }
-
- // we do not want the menu to end with a separator
- if (!tomenu.empty()
- && tomenu.items_.back().kind() == MenuItem::Separator)
- tomenu.items_.pop_back();
-
- // Check whether the shortcuts are unique
- tomenu.checkShortcuts();
-}
-
-
-void MenuBackend::read(Lexer & lex)
-{
- enum Menutags {
- md_menu = 1,
- md_menubar,
- md_endmenuset,
- md_last
- };
-
- struct keyword_item menutags[md_last - 1] = {
- { "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;
- }
-
- lex.pushTable(menutags, md_last - 1);
- if (lyxerr.debugging(Debug::PARSER))
- lex.printTable(lyxerr);
-
- bool quit = false;
-
- while (lex.isOK() && !quit) {
- switch (lex.lex()) {
- case md_menubar:
- menubar_.read(lex);
- break;
- case md_menu: {
- lex.next(true);
- docstring const name = lex.getDocString();
- if (hasMenu(name)) {
- getMenu(name).read(lex);
- } else {
- Menu menu(name);
- menu.read(lex);
- add(menu);
- }
- break;
- }
- case md_endmenuset:
- quit = true;
- break;
- default:
- lex.printError("menubackend::read: "
- "Unknown menu tag: `$$Token'");
- break;
- }
- }
- lex.popTable();
-}
-
-
-void MenuBackend::add(Menu const & menu)
-{
- menulist_.push_back(menu);
-}
-
-
-bool MenuBackend::hasMenu(docstring const & name) const
-{
- return find_if(begin(), end(), MenuNamesEqual(name)) != end();
-}
-
-
-Menu const & MenuBackend::getMenu(docstring const & name) const
-{
- const_iterator cit = find_if(begin(), end(), MenuNamesEqual(name));
- if (cit == end())
- lyxerr << "No submenu named " << to_utf8(name) << endl;
- BOOST_ASSERT(cit != end());
- return (*cit);
-}
-
-
-Menu & MenuBackend::getMenu(docstring const & name)
-{
- iterator it = find_if(begin(), end(), MenuNamesEqual(name));
- if (it == end())
- lyxerr << "No submenu named " << to_utf8(name) << endl;
- BOOST_ASSERT(it != end());
- return (*it);
-}
-
-
-Menu const & MenuBackend::getMenubar() const
-{
- return menubar_;
-}
-
-
-} // namespace lyx
+++ /dev/null
-// -*- C++ -*-
-/**
- * \file MenuBackend.h
- * This file is part of LyX, the document processor.
- * Licence details can be found in the file COPYING.
- *
- * \author Lars Gullik Bjønnes
- * \author Jean-Marc Lasgouttes
- *
- * Full author contact details are available in file CREDITS.
- */
-
-#ifndef MENUBACKEND_H
-#define MENUBACKEND_H
-
-#include "FuncStatus.h"
-#include "FuncRequest.h"
-
-#include <boost/shared_ptr.hpp>
-
-#include <vector>
-
-
-namespace lyx {
-
-class Lexer;
-class Buffer;
-class Menu;
-
-///
-class MenuItem {
-public:
- /// The type of elements that can be in a menu
- enum Kind {
- ///
- Command,
- ///
- Submenu,
- ///
- Separator,
- /** This is the list of last opened file,
- typically for the File menu. */
- Lastfiles,
- /** This is the list of opened Documents,
- typically for the Documents menu. */
- Documents,
- /** This is the bookmarks */
- Bookmarks,
- ///
- Toc,
- /** This is a list of viewable formats
- typically for the File->View menu. */
- ViewFormats,
- /** This is a list of updatable formats
- typically for the File->Update menu. */
- UpdateFormats,
- /** This is a list of exportable formats
- typically for the File->Export menu. */
- ExportFormats,
- /** This is a list of importable formats
- typically for the File->Export menu. */
- ImportFormats,
- /** This is the list of elements available
- * for insertion into document. */
- CharStyles,
- /** This is the list of user-configurable
- insets to insert into document */
- Custom,
- /** This is the list of XML elements to
- insert into the document */
- Elements,
- /** This is the list of floats that we can
- insert a list for. */
- FloatListInsert,
- /** This is the list of floats that we can
- insert. */
- FloatInsert,
- /** This is the list of selections that can
- be pasted. */
- PasteRecent,
- /** toolbars */
- Toolbars,
- /** Available branches in document */
- Branches
- };
-
- explicit MenuItem(Kind kind);
-
- MenuItem(Kind kind,
- docstring const & label,
- docstring const & submenu = docstring(),
- bool optional = false);
-
- MenuItem(Kind kind,
- docstring const & label,
- FuncRequest const & func,
- bool optional = false);
-
- /// This one is just to please boost::shared_ptr<>
- ~MenuItem();
- /// The label of a given menuitem
- docstring const label() const;
- /// The keyboard shortcut (usually underlined in the entry)
- docstring const shortcut() const;
- /// The complete label, with label and shortcut separated by a '|'
- docstring const fulllabel() const { return label_;}
- /// The kind of entry
- Kind kind() const { return kind_; }
- /// the action (if relevant)
- FuncRequest const & func() const { return func_; }
- /// returns true if the entry should be ommited when disabled
- bool optional() const { return optional_; }
- /// returns the status of the lfun associated with this entry
- FuncStatus const & status() const { return status_; }
- /// returns the status of the lfun associated with this entry
- FuncStatus & status() { return status_; }
- /// returns the status of the lfun associated with this entry
- void status(FuncStatus const & status) { status_ = status; }
- ///returns the binding associated to this action.
- docstring const binding() const;
- /// the description of the submenu (if relevant)
- docstring const & submenuname() const { return submenuname_; }
- /// set the description of the submenu
- void submenuname(docstring const & name) { submenuname_ = name; }
- ///
- Menu * submenu() const { return submenu_.get(); }
- ///
- void submenu(Menu * menu);
-
-private:
- //friend class MenuBackend;
- ///
- Kind kind_;
- ///
- docstring label_;
- ///
- FuncRequest func_;
- ///
- docstring submenuname_;
- ///
- bool optional_;
- ///
- FuncStatus status_;
- ///
- boost::shared_ptr<Menu> submenu_;
-};
-
-
-///
-class Menu {
-public:
- ///
- typedef std::vector<MenuItem> ItemList;
- ///
- typedef ItemList::const_iterator const_iterator;
- ///
- typedef ItemList::size_type size_type;
- ///
- explicit Menu(docstring const & name = docstring()) : name_(name) {}
- /// Add the menu item unconditionally
- Menu & add(MenuItem const &);
- /// Checks the associated FuncRequest status before adding the
- /// menu item.
- Menu & addWithStatusCheck(MenuItem const &);
- ///
- Menu & read(Lexer &);
- ///
- docstring const & name() const { return name_; }
- ///
- bool empty() const { return items_.empty(); }
- /// Clear the menu content.
- void clear() { items_.clear(); }
- ///
- ItemList::size_type size() const { return items_.size(); }
- ///
- MenuItem const & operator[](size_type) const;
- ///
- bool hasFunc(FuncRequest const &) const;
- ///
- const_iterator begin() const { return items_.begin(); }
- ///
- const_iterator end() const { return items_.end(); }
-
- // Check whether the menu shortcuts are unique
- void checkShortcuts() const;
-
- // search for func in this menu iteratively, and put menu
- // names in a stack.
- bool searchMenu(FuncRequest const & func, std::vector<docstring> & names)
- const;
-
-private:
- friend class MenuBackend;
- ///
- ItemList items_;
- ///
- docstring name_;
-};
-
-
-///
-class MenuBackend {
-public:
- ///
- typedef std::vector<Menu> MenuList;
- ///
- typedef MenuList::const_iterator const_iterator;
- ///
- typedef MenuList::iterator iterator;
- ///
- MenuBackend() {}
- ///
- void read(Lexer &);
- ///
- void add(Menu const &);
- ///
- bool hasMenu(docstring const &) const;
- ///
- Menu & getMenu(docstring const &);
- ///
- Menu const & getMenu(docstring const &) const;
- ///
- Menu const & getMenubar() const;
- ///
- bool empty() const { return menulist_.empty(); }
- /** 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
- */
- void specialMenu(Menu const &);
- ///
- Menu const & specialMenu() { return specialmenu_; }
-
- /// 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
- */
- void expand(Menu const & frommenu, Menu & tomenu,
- Buffer const *) const;
- ///
- const_iterator begin() const { return menulist_.begin(); }
- ///
- iterator begin() { return menulist_.begin(); }
- ///
- const_iterator end() const { return menulist_.end(); }
- ///
- iterator end() { return menulist_.end(); }
-
-private:
- ///
- MenuList menulist_;
- ///
- Menu menubar_;
- ///
- Menu specialmenu_;
-};
-
-} // namespace lyx
-
-#endif // MENUBACKEND_H
class FuncStatus;
class Inset;
class Lexer;
-class MenuBackend;
struct RGBColor;
namespace frontend {
*/
virtual void unregisterSocketCallback(int fd) = 0;
- ///
- virtual MenuBackend const & menuBackend() const = 0;
- virtual MenuBackend & menuBackend() = 0;
-
virtual bool searchMenu(FuncRequest const & func,
std::vector<docstring> & names) const = 0;
};
void GuiApplication::readMenus(Lexer & lex)
{
- menuBackend().read(lex);
+ menus().read(lex);
}
bool GuiApplication::searchMenu(FuncRequest const & func,
vector<docstring> & names) const
{
- return menuBackend().getMenubar().searchMenu(func, names);
+ return menus().getMenubar().searchMenu(func, names);
}
virtual Clipboard & clipboard();
virtual Selection & selection();
virtual FontLoader & fontLoader() { return font_loader_; }
- MenuBackend const & menuBackend() const { return menus_; }
- MenuBackend & menuBackend() { return menus_; }
virtual int exec();
virtual void exit(int status);
virtual bool event(QEvent * e);
#include <config.h>
-#include "GuiView.h"
+#include "GuiPopupMenu.h"
#include "Action.h"
#include "GuiApplication.h"
-#include "GuiPopupMenu.h"
+#include "GuiView.h"
#include "qt_helpers.h"
#include "LyXFunc.h"
-#include "MenuBackend.h"
#include "support/debug.h"
-#include "support/lstrings.h"
namespace lyx {
namespace frontend {
bool topLevelMenu)
: QMenu(owner), owner_(owner)
{
- name_ = toqstr(mi.submenuname());
+ name_ = mi.submenuname();
setTitle(label(mi));
// Here, We make sure that theLyXFunc points to the correct LyXView.
theLyXFunc().setLyXView(owner_);
- MenuBackend const & menubackend = guiApp->menuBackend();
- Menu const & fromLyxMenu = menubackend.getMenu(qstring_to_ucs4(name_));
- menubackend.expand(fromLyxMenu, topLevelMenu_, owner_->buffer());
+ Menus const & menus = guiApp->menus();
+ Menu const & fromLyxMenu = menus.getMenu(name_);
+ menus.expand(fromLyxMenu, topLevelMenu_, owner_->buffer());
- if (!menubackend.hasMenu(topLevelMenu_.name())) {
+ if (!menus.hasMenu(topLevelMenu_.name())) {
LYXERR(Debug::GUI, "\tWARNING: menu seems empty"
- << to_utf8(topLevelMenu_.name()));
+ << fromqstr(topLevelMenu_.name()));
}
populate(this, &topLevelMenu_);
}
void GuiPopupMenu::populate(QMenu * qMenu, Menu * menu)
{
- LYXERR(Debug::GUI, "populating menu " << to_utf8(menu->name()));
+ LYXERR(Debug::GUI, "populating menu " << fromqstr(menu->name()));
if (menu->size() == 0) {
- LYXERR(Debug::GUI, "\tERROR: empty menu " << to_utf8(menu->name()));
+ LYXERR(Debug::GUI, "\tERROR: empty menu " << fromqstr(menu->name()));
return;
}
LYXERR(Debug::GUI, " ***** menu entries " << menu->size());
} else { // we have a MenuItem::Command
LYXERR(Debug::GUI, "creating Menu Item "
- << to_utf8(m->label()));
+ << fromqstr(m->label()));
- Action * action = new Action(*(owner_),
+ Action * action = new Action(*owner_,
QIcon(), label(*m), m->func(), QString());
qMenu->addAction(action);
}
QString GuiPopupMenu::label(MenuItem const & mi) const
{
- docstring label = support::subst(mi.label(),
- from_ascii("&"), from_ascii("&&"));
-
- docstring const shortcut = mi.shortcut();
- if (!shortcut.empty()) {
- size_t pos = label.find(shortcut);
- if (pos != docstring::npos)
- label.insert(pos, 1, char_type('&'));
+ 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, "&");
}
- docstring const binding = mi.binding();
- if (!binding.empty())
+ QString const binding = mi.binding();
+ if (!binding.isEmpty())
label += '\t' + binding;
- return toqstr(label);
+ return label;
}
#ifndef GUIPOPUPMENU_H
#define GUIPOPUPMENU_H
-#include "MenuBackend.h"
+#include "Menus.h"
#include <QMenu>
#include "GuiApplication.h"
#include "GuiKeySymbol.h"
#include "GuiPainter.h"
-#include "GuiPopupMenu.h"
#include "GuiView.h"
#include "KeySymbol.h"
#include "Language.h"
#include <QMacStyle>
#endif
#include <QMainWindow>
+#include <QMenu>
#include <QPainter>
#include <QPalette>
#include <QScrollBar>
* Licence details can be found in the file COPYING.
*
* \author John Levon
+ * \author Asger Alstrup
+ * \author Lars Gullik Bjønnes
+ * \author Jean-Marc Lasgouttes
+ * \author André Pönitz
+ * \author Dekel Tsur
+ * \author Martin Vermeer
*
* Full author contact details are available in file CREDITS.
*/
#include "GuiPopupMenu.h"
#include "GuiView.h"
-#include "qt_helpers.h"
+#include "BranchList.h"
+#include "Buffer.h"
+#include "BufferList.h"
+#include "BufferParams.h"
+#include "Converter.h"
+#include "CutAndPaste.h"
+#include "Floating.h"
+#include "FloatList.h"
+#include "Format.h"
+#include "KeyMap.h"
+#include "Session.h"
+#include "LyXAction.h"
+#include "LyX.h" // for lastfiles
+#include "LyXFunc.h"
+#include "Lexer.h"
+#include "Paragraph.h"
+#include "TextClass.h"
+#include "TocBackend.h"
+#include "ToolbarBackend.h"
+
+#include "frontends/Application.h"
+#include "support/convert.h"
#include "support/debug.h"
+#include "support/filetools.h"
+#include "support/gettext.h"
+#include "support/lstrings.h"
+
+#include <boost/bind.hpp>
+
+#include "qt_helpers.h"
#include <QCursor>
#include <QMenuBar>
+#include <algorithm>
+#include <ostream>
+
+using namespace std;
+using boost::bind;
+using namespace lyx::support;
+
namespace lyx {
namespace frontend {
+namespace {
+
+class MenuNamesEqual
+{
+public:
+ MenuNamesEqual(QString const & name) : name_(name) {}
+ bool operator()(Menu const & menu) const { return menu.name() == name_; }
+private:
+ QString name_;
+};
+
+} // namespace anon
+
// MacOSX specific stuff is at the end.
void Menus::fillMenuBar(GuiView * view)
macxMenuBarInit(view);
#endif
- LYXERR(Debug::GUI, "populating menu bar" << to_utf8(getMenubar().name()));
+ LYXERR(Debug::GUI, "populating menu bar" << fromqstr(getMenubar().name()));
if (getMenubar().size() == 0) {
LYXERR(Debug::GUI, "\tERROR: empty menu bar"
- << to_utf8(getMenubar().name()));
+ << fromqstr(getMenubar().name()));
return;
}
else {
for (; m != end; ++m) {
if (m->kind() != MenuItem::Submenu) {
- LYXERR(Debug::GUI, "\tERROR: not a submenu " << to_utf8(m->label()));
+ LYXERR(Debug::GUI, "\tERROR: not a submenu " << fromqstr(m->label()));
continue;
}
- LYXERR(Debug::GUI, "menu bar item " << to_utf8(m->label())
- << " is a submenu named " << to_utf8(m->submenuname()));
+ LYXERR(Debug::GUI, "menu bar item " << fromqstr(m->label())
+ << " is a submenu named " << fromqstr(m->submenuname()));
- docstring name = m->submenuname();
+ QString name = m->submenuname();
if (!hasMenu(name)) {
- LYXERR(Debug::GUI, "\tERROR: " << to_utf8(name)
+ LYXERR(Debug::GUI, "\tERROR: " << fromqstr(name)
<< " submenu has no menu!");
continue;
}
GuiPopupMenu * qMenu = new GuiPopupMenu(view, *m, true);
view->menuBar()->addMenu(qMenu);
- name_map_[toqstr(name)] = qMenu;
+ name_map_[name] = qMenu;
}
}
QMenu * Menus::menu(QString const & name)
{
- LYXERR(Debug::GUI, "Context menu requested: "
- << qstring_to_ucs4(name));
+ LYXERR(Debug::GUI, "Context menu requested: " << fromqstr(name));
GuiPopupMenu * menu = name_map_.value(name, 0);
if (!menu)
- LYXERR0("resquested context menu not found: "
- << qstring_to_ucs4(name));
+ LYXERR0("resquested context menu not found: " << fromqstr(name));
return menu;
}
*/
/* The entries of our special mac menu. If we add support for
- * special entries in MenuBackend, we could imagine something
+ * 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
};
const size_t num_entries = sizeof(entries) / sizeof(MacMenuEntry);
- // the special menu for MenuBackend.
+ // the special menu for Menus.
Menu special;
for (size_t i = 0 ; i < num_entries ; ++i) {
FuncRequest const func(entries[i].action,
from_utf8(entries[i].arg));
- special.add(MenuItem(MenuItem::Command,
- from_utf8(entries[i].label),
- func));
+ special.add(MenuItem(MenuItem::Command, entries[i].label, func));
}
specialMenu(special);
QMenu * qMenu = view->menuBar()->addMenu("special");
// we do not use 'special' because it is a temporary variable,
- // whereas MenuBackend::specialMenu points to a persistent
+ // whereas Menus::specialMenu points to a persistent
// copy.
Menu::const_iterator cit = specialMenu().begin();
Menu::const_iterator end = specialMenu().end();
for (size_t i = 0 ; cit != end ; ++cit, ++i) {
- Action * action = new Action(*view, QIcon(),
- toqstr(cit->label()),
+ Action * action = new Action(*view, QIcon(), cit->label(),
cit->func(), QString());
action->setMenuRole(entries[i].role);
qMenu->addAction(action);
}
}
+
+MenuItem::MenuItem(Kind kind)
+ : kind_(kind), optional_(false)
+{}
+
+
+MenuItem::MenuItem(Kind kind, QString const & label,
+ QString const & submenu, bool optional)
+ : kind_(kind), label_(label),
+ submenuname_(submenu), optional_(optional)
+{
+ BOOST_ASSERT(kind == Submenu);
+}
+
+
+MenuItem::MenuItem(Kind kind, QString const & label,
+ FuncRequest const & func, bool optional)
+ : kind_(kind), label_(label), func_(func), optional_(optional)
+{
+ func_.origin = FuncRequest::MENU;
+}
+
+
+MenuItem::~MenuItem()
+{}
+
+
+void MenuItem::submenu(Menu * menu)
+{
+ submenu_.reset(menu);
+}
+
+
+QString MenuItem::label() const
+{
+ return label_.split('|')[0];
+}
+
+
+QString MenuItem::shortcut() const
+{
+ return label_.contains('|') ? label_.split('|')[1] : QString();
+}
+
+
+QString MenuItem::binding() const
+{
+ if (kind_ != Command)
+ return QString();
+
+ // Get the keys bound to this action, but keep only the
+ // first one later
+ KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(func_);
+
+ if (bindings.size())
+ return toqstr(bindings.begin()->print(KeySequence::ForGui));
+
+ LYXERR(Debug::KBMAP, "No binding for "
+ << lyxaction.getActionName(func_.action)
+ << '(' << func_.argument() << ')');
+ return QString();
+}
+
+
+Menu & Menu::add(MenuItem const & i)
+{
+ items_.push_back(i);
+ return *this;
+}
+
+
+Menu & Menu::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: {
+ if (i.submenu()) {
+ bool enabled = false;
+ for (const_iterator cit = i.submenu()->begin();
+ cit != i.submenu()->end(); ++cit) {
+ if ((cit->kind() == MenuItem::Command
+ || cit->kind() == MenuItem::Submenu)
+ && cit->status().enabled()) {
+ enabled = true;
+ break;
+ }
+ }
+ if (enabled || !i.optional()) {
+ items_.push_back(i);
+ items_.back().status().enabled(enabled);
+ }
+ }
+ else
+ items_.push_back(i);
+ break;
+ }
+
+ case MenuItem::Separator:
+ if (!items_.empty() && items_.back().kind() != MenuItem::Separator)
+ items_.push_back(i);
+ break;
+
+ default:
+ items_.push_back(i);
+ }
+
+ return *this;
+}
+
+
+Menu & Menu::read(Lexer & lex)
+{
+ enum Menutags {
+ md_item = 1,
+ md_branches,
+ md_documents,
+ md_bookmarks,
+ md_charstyles,
+ md_custom,
+ md_elements,
+ md_endmenu,
+ md_exportformats,
+ md_importformats,
+ 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_last
+ };
+
+ struct keyword_item menutags[md_last - 1] = {
+ { "bookmarks", md_bookmarks },
+ { "branches", md_branches },
+ { "charstyles", md_charstyles },
+ { "custom", md_custom },
+ { "documents", md_documents },
+ { "elements", md_elements },
+ { "end", md_endmenu },
+ { "exportformats", md_exportformats },
+ { "floatinsert", md_floatinsert },
+ { "floatlistinsert", md_floatlistinsert },
+ { "importformats", md_importformats },
+ { "item", md_item },
+ { "lastfiles", md_lastfiles },
+ { "optitem", md_optitem },
+ { "optsubmenu", md_optsubmenu },
+ { "pasterecent", md_pasterecent },
+ { "separator", md_separator },
+ { "submenu", md_submenu },
+ { "toc", md_toc },
+ { "toolbars", md_toolbars },
+ { "updateformats", md_updateformats },
+ { "viewformats", md_viewformats }
+ };
+
+ lex.pushTable(menutags, md_last - 1);
+ if (lyxerr.debugging(Debug::PARSER))
+ lex.printTable(lyxerr);
+
+ 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);
+ add(MenuItem(MenuItem::Command, toqstr(name), func, optional));
+ 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_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("Menu::read: "
+ "Unknown menu tag: `$$Token'");
+ break;
+ }
+ }
+ lex.popTable();
+ return *this;
+}
+
+
+MenuItem const & Menu::operator[](size_type i) const
+{
+ return items_[i];
+}
+
+
+bool Menu::hasFunc(FuncRequest const & func) const
+{
+ return find_if(begin(), end(),
+ bind(equal_to<FuncRequest>(),
+ bind(&MenuItem::func, _1),
+ func)) != end();
+}
+
+void Menu::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))
+ lyxerr << "Menu warning: menu entry \""
+ << fromqstr(it1->label())
+ << "\" does not contain shortcut `"
+ << fromqstr(shortcut) << "'." << endl;
+ for (const_iterator it2 = begin(); it2 != it1 ; ++it2) {
+ if (!it2->shortcut().compare(shortcut, Qt::CaseInsensitive)) {
+ lyxerr << "Menu warning: menu entries "
+ << '"' << fromqstr(it1->fulllabel())
+ << "\" and \"" << fromqstr(it2->fulllabel())
+ << "\" share the same shortcut."
+ << endl;
+ }
+ }
+ }
+}
+
+
+bool Menu::searchMenu(FuncRequest const & func, vector<docstring> & 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()));
+ Menu const & submenu = *m->submenu();
+ if (submenu.searchMenu(func, names))
+ return true;
+ names.pop_back();
+ }
+ }
+ return false;
+}
+
+
+void Menus::specialMenu(Menu const & menu)
+{
+ specialmenu_ = menu;
+}
+
+
+namespace {
+
+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 expandLastfiles(Menu & tomenu)
+{
+ LastFilesSection::LastFiles const & lf = LyX::cref().session().lastFiles().lastFiles();
+ LastFilesSection::LastFiles::const_iterator lfit = lf.begin();
+
+ int ii = 1;
+
+ for (; lfit != lf.end() && ii < 10; ++lfit, ++ii) {
+ string const file = lfit->absFilename();
+ QString const label = QString("%1. %2|%3").arg(ii)
+ .arg(toqstr(makeDisplayPath(file, 30))).arg(ii);
+ tomenu.add(MenuItem(MenuItem::Command, label, FuncRequest(LFUN_FILE_OPEN, file)));
+ }
+}
+
+
+void expandDocuments(Menu & tomenu)
+{
+ Buffer * first = theBufferList().first();
+ if (first) {
+ Buffer * b = first;
+ int ii = 1;
+
+ // We cannot use a for loop as the buffer list cycles.
+ do {
+ QString label = toqstr(b->fileName().displayName(20));
+ if (!b->isClean())
+ label += "*";
+ if (ii < 10)
+ label = QString::number(ii) + ". " + label + '|' + QString::number(ii);
+ tomenu.add(MenuItem(MenuItem::Command, label,
+ FuncRequest(LFUN_BUFFER_SWITCH, b->absFileName())));
+
+ b = theBufferList().next(b);
+ ++ii;
+ } while (b != first);
+ } else {
+ tomenu.add(MenuItem(MenuItem::Command, qt_("No Documents Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ }
+}
+
+
+void expandBookmarks(Menu & tomenu)
+{
+ lyx::BookmarksSection const & bm = LyX::cref().session().bookmarks();
+
+ for (size_t i = 1; i <= bm.size(); ++i) {
+ if (bm.isValid(i)) {
+ string const file = bm.bookmark(i).filename.absFilename();
+ QString const label = QString("%1. %2|%3").arg(i)
+ .arg(toqstr(makeDisplayPath(file, 20))).arg(i);
+ tomenu.add(MenuItem(MenuItem::Command, label,
+ FuncRequest(LFUN_BOOKMARK_GOTO, convert<docstring>(i))));
+ }
+ }
+}
+
+
+void expandFormats(MenuItem::Kind kind, Menu & tomenu, Buffer const * buf)
+{
+ if (!buf && kind != MenuItem::ImportFormats) {
+ tomenu.add(MenuItem(MenuItem::Command,
+ qt_("No Document Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+
+ typedef vector<Format const *> Formats;
+ Formats formats;
+ kb_action action;
+
+ switch (kind) {
+ case MenuItem::ImportFormats:
+ formats = theConverters().importableFormats();
+ action = LFUN_BUFFER_IMPORT;
+ break;
+ case MenuItem::ViewFormats:
+ formats = buf->exportableFormats(true);
+ action = LFUN_BUFFER_VIEW;
+ break;
+ case MenuItem::UpdateFormats:
+ formats = buf->exportableFormats(true);
+ action = LFUN_BUFFER_UPDATE;
+ break;
+ default:
+ formats = buf->exportableFormats(false);
+ action = LFUN_BUFFER_EXPORT;
+ }
+ sort(formats.begin(), formats.end(), &compareFormat);
+
+ Formats::const_iterator fit = formats.begin();
+ Formats::const_iterator end = formats.end();
+ for (; fit != end ; ++fit) {
+ if ((*fit)->dummy())
+ continue;
+ QString label = toqstr((*fit)->prettyname());
+ QString const shortcut = toqstr((*fit)->shortcut());
+
+ switch (kind) {
+ case MenuItem::ImportFormats:
+ // FIXME: This is a hack, we should rather solve
+ // FIXME: bug 2488 instead.
+ if ((*fit)->name() == "text")
+ label = qt_("Plain Text");
+ else if ((*fit)->name() == "textparagraph")
+ label = qt_("Plain Text, Join Lines");
+ label += "...";
+ break;
+ case MenuItem::ViewFormats:
+ case MenuItem::ExportFormats:
+ case MenuItem::UpdateFormats:
+ if (!(*fit)->documentFormat())
+ continue;
+ break;
+ default:
+ BOOST_ASSERT(false);
+ break;
+ }
+ // FIXME: if we had proper support for translating the
+ // format names defined in configure.py, there would
+ // not be a need to check whether the shortcut is
+ // correct. If we add it uncondiitonally, it would
+ // create useless warnings on bad shortcuts
+ if (!shortcut.isEmpty() && label.contains(shortcut))
+ label += '|' + shortcut;
+
+ if (buf)
+ tomenu.addWithStatusCheck(MenuItem(MenuItem::Command, label,
+ FuncRequest(action, (*fit)->name())));
+ else
+ tomenu.add(MenuItem(MenuItem::Command, label,
+ FuncRequest(action, (*fit)->name())));
+ }
+}
+
+
+void expandFloatListInsert(Menu & tomenu, Buffer const * buf)
+{
+ if (!buf) {
+ tomenu.add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+
+ FloatList const & floats = buf->params().documentClass().floats();
+ FloatList::const_iterator cit = floats.begin();
+ FloatList::const_iterator end = floats.end();
+ for (; cit != end; ++cit) {
+ tomenu.addWithStatusCheck(MenuItem(MenuItem::Command,
+ qt_(cit->second.listName()),
+ FuncRequest(LFUN_FLOAT_LIST,
+ cit->second.type())));
+ }
+}
+
+
+void expandFloatInsert(Menu & tomenu, Buffer const * buf)
+{
+ if (!buf) {
+ tomenu.add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+
+ FloatList const & floats = buf->params().documentClass().floats();
+ FloatList::const_iterator cit = floats.begin();
+ FloatList::const_iterator end = floats.end();
+ for (; cit != end; ++cit) {
+ // normal float
+ QString const label = qt_(cit->second.name());
+ tomenu.addWithStatusCheck(MenuItem(MenuItem::Command, label,
+ FuncRequest(LFUN_FLOAT_INSERT,
+ cit->second.type())));
+ }
+}
+
+
+void expandFlexInsert(Menu & tomenu, Buffer const * buf, string s)
+{
+ if (!buf) {
+ tomenu.add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+ TextClass::InsetLayouts const & insetLayouts =
+ buf->params().documentClass().insetLayouts();
+ TextClass::InsetLayouts::const_iterator cit = insetLayouts.begin();
+ TextClass::InsetLayouts::const_iterator end = insetLayouts.end();
+ for (; cit != end; ++cit) {
+ docstring const label = cit->first;
+ if (cit->second.lyxtype() == s)
+ tomenu.addWithStatusCheck(MenuItem(MenuItem::Command,
+ toqstr(label), FuncRequest(LFUN_FLEX_INSERT,
+ label)));
+ }
+}
+
+
+size_t const max_number_of_items = 25;
+
+void expandToc2(Menu & tomenu, Toc const & toc_list,
+ size_t from, size_t to, int depth)
+{
+ int shortcut_count = 0;
+
+ // check whether depth is smaller than the smallest depth in toc.
+ int min_depth = 1000;
+ for (size_t i = from; i < to; ++i)
+ min_depth = min(min_depth, toc_list[i].depth());
+ if (min_depth > depth)
+ depth = min_depth;
+
+ if (to - from <= max_number_of_items) {
+ for (size_t i = from; i < to; ++i) {
+ QString label(4 * max(0, toc_list[i].depth() - depth), ' ');
+ label += limitStringLength(toc_list[i].str());
+ if (toc_list[i].depth() == depth
+ && shortcut_count < 9) {
+ if (label.contains(QString::number(shortcut_count + 1)))
+ label += '|' + QString::number(++shortcut_count);
+ }
+ tomenu.add(MenuItem(MenuItem::Command, label,
+ FuncRequest(toc_list[i].action())));
+ }
+ } else {
+ size_t pos = from;
+ while (pos < to) {
+ size_t new_pos = pos + 1;
+ while (new_pos < to &&
+ toc_list[new_pos].depth() > depth)
+ ++new_pos;
+
+ QString label(4 * max(0, toc_list[pos].depth() - depth), ' ');
+ label += limitStringLength(toc_list[pos].str());
+ if (toc_list[pos].depth() == depth &&
+ shortcut_count < 9) {
+ if (label.contains(QString::number(shortcut_count + 1)))
+ label += '|' + QString::number(++shortcut_count);
+ }
+ if (new_pos == pos + 1) {
+ tomenu.add(MenuItem(MenuItem::Command,
+ label, FuncRequest(toc_list[pos].action())));
+ } else {
+ MenuItem item(MenuItem::Submenu, label);
+ item.submenu(new Menu);
+ expandToc2(*item.submenu(),
+ toc_list, pos, new_pos, depth + 1);
+ tomenu.add(item);
+ }
+ pos = new_pos;
+ }
+ }
+}
+
+
+void expandToc(Menu & tomenu, Buffer const * buf)
+{
+ // To make things very cleanly, we would have to pass buf to
+ // all MenuItem constructors and to expandToc2. However, we
+ // know that all the entries in a TOC will be have status_ ==
+ // OK, so we avoid this unnecessary overhead (JMarc)
+
+ if (!buf) {
+ tomenu.add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+
+ Buffer* cbuf = const_cast<Buffer*>(buf);
+ cbuf->tocBackend().update();
+ cbuf->structureChanged();
+
+ // Add an entry for the master doc if this is a child doc
+ Buffer const * const master = buf->masterBuffer();
+ if (buf != master) {
+ ParIterator const pit = par_iterator_begin(master->inset());
+ string const arg = convert<string>(pit->id());
+ FuncRequest f(LFUN_PARAGRAPH_GOTO, arg);
+ tomenu.add(MenuItem(MenuItem::Command, qt_("Master Document"), f));
+ }
+
+ FloatList const & floatlist = buf->params().documentClass().floats();
+ TocList const & toc_list = buf->tocBackend().tocs();
+ TocList::const_iterator cit = toc_list.begin();
+ TocList::const_iterator end = toc_list.end();
+ for (; cit != end; ++cit) {
+ // Handle this later
+ if (cit->first == "tableofcontents")
+ continue;
+
+ // All the rest is for floats
+ auto_ptr<Menu> menu(new Menu);
+ TocIterator ccit = cit->second.begin();
+ TocIterator eend = cit->second.end();
+ for (; ccit != eend; ++ccit) {
+ QString const label = limitStringLength(ccit->str());
+ menu->add(MenuItem(MenuItem::Command, label,
+ FuncRequest(ccit->action())));
+ }
+ string const & floatName = floatlist.getType(cit->first).listName();
+ QString label;
+ if (!floatName.empty())
+ label = qt_(floatName);
+ // BUG3633: listings is not a proper float so its name
+ // is not shown in floatlist.
+ 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 == "marginalnote")
+ label = qt_("List of Marginal notes");
+ else if (cit->first == "note")
+ label = qt_("List of Notes");
+ else if (cit->first == "footnote")
+ label = qt_("List of Foot notes");
+ else if (cit->first == "label")
+ 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");
+ MenuItem item(MenuItem::Submenu, label);
+ item.submenu(menu.release());
+ tomenu.add(item);
+ }
+
+ // Handle normal TOC
+ cit = toc_list.find("tableofcontents");
+ if (cit == end) {
+ tomenu.addWithStatusCheck(MenuItem(MenuItem::Command,
+ qt_("No Table of contents"),
+ FuncRequest()));
+ } else {
+ expandToc2(tomenu, cit->second, 0, cit->second.size(), 0);
+ }
+}
+
+
+void expandPasteRecent(Menu & tomenu)
+{
+ vector<docstring> const sel = cap::availableSelections();
+
+ vector<docstring>::const_iterator cit = sel.begin();
+ vector<docstring>::const_iterator end = sel.end();
+
+ for (unsigned int index = 0; cit != end; ++cit, ++index) {
+ tomenu.add(MenuItem(MenuItem::Command, toqstr(*cit),
+ FuncRequest(LFUN_PASTE, convert<string>(index))));
+ }
+}
+
+
+void expandToolbars(Menu & tomenu)
+{
+ //
+ // extracts the toolbars from the backend
+ ToolbarBackend::Toolbars::const_iterator cit = toolbarbackend.begin();
+ ToolbarBackend::Toolbars::const_iterator end = toolbarbackend.end();
+
+ for (; cit != end; ++cit) {
+ QString label = qt_(cit->gui_name);
+ // frontends are not supposed to turn on/off toolbars,
+ // if they cannot update ToolbarBackend::flags. That
+ // is to say, ToolbarsBackend::flags should reflect
+ // the true state of toolbars.
+ //
+ // menu is displayed as
+ // on/off review
+ // and
+ // review (auto)
+ // in the case of auto.
+ if (cit->flags & ToolbarInfo::AUTO)
+ label += qt_(" (auto)");
+ tomenu.add(MenuItem(MenuItem::Command, label,
+ FuncRequest(LFUN_TOOLBAR_TOGGLE, cit->name + " allowauto")));
+ }
+}
+
+
+void expandBranches(Menu & tomenu, Buffer const * buf)
+{
+ if (!buf) {
+ tomenu.add(MenuItem(MenuItem::Command,
+ qt_("No Document Open!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+
+ BufferParams const & params = buf->masterBuffer()->params();
+ if (params.branchlist().empty()) {
+ tomenu.add(MenuItem(MenuItem::Command,
+ qt_("No Branch in Document!"),
+ FuncRequest(LFUN_NOACTION)));
+ return;
+ }
+
+ BranchList::const_iterator cit = params.branchlist().begin();
+ BranchList::const_iterator end = params.branchlist().end();
+
+ for (int ii = 1; cit != end; ++cit, ++ii) {
+ docstring label = cit->getBranch();
+ if (ii < 10)
+ label = convert<docstring>(ii) + ". " + label + char_type('|') + convert<docstring>(ii);
+ tomenu.addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(label),
+ FuncRequest(LFUN_BRANCH_INSERT,
+ cit->getBranch())));
+ }
+}
+
+
+} // namespace anon
+
+
+void Menus::expand(Menu const & frommenu, Menu & tomenu,
+ Buffer const * buf) const
+{
+ if (!tomenu.empty())
+ tomenu.clear();
+
+ for (Menu::const_iterator cit = frommenu.begin();
+ cit != frommenu.end() ; ++cit) {
+ switch (cit->kind()) {
+ case MenuItem::Lastfiles:
+ expandLastfiles(tomenu);
+ break;
+
+ case MenuItem::Documents:
+ expandDocuments(tomenu);
+ break;
+
+ case MenuItem::Bookmarks:
+ expandBookmarks(tomenu);
+ break;
+
+ case MenuItem::ImportFormats:
+ case MenuItem::ViewFormats:
+ case MenuItem::UpdateFormats:
+ case MenuItem::ExportFormats:
+ expandFormats(cit->kind(), tomenu, buf);
+ break;
+
+ case MenuItem::CharStyles:
+ expandFlexInsert(tomenu, buf, "charstyle");
+ break;
+
+ case MenuItem::Custom:
+ expandFlexInsert(tomenu, buf, "custom");
+ break;
+
+ case MenuItem::Elements:
+ expandFlexInsert(tomenu, buf, "element");
+ break;
+
+ case MenuItem::FloatListInsert:
+ expandFloatListInsert(tomenu, buf);
+ break;
+
+ case MenuItem::FloatInsert:
+ expandFloatInsert(tomenu, buf);
+ break;
+
+ case MenuItem::PasteRecent:
+ expandPasteRecent(tomenu);
+ break;
+
+ case MenuItem::Toolbars:
+ expandToolbars(tomenu);
+ break;
+
+ case MenuItem::Branches:
+ expandBranches(tomenu, buf);
+ break;
+
+ case MenuItem::Toc:
+ expandToc(tomenu, buf);
+ break;
+
+ case MenuItem::Submenu: {
+ MenuItem item(*cit);
+ item.submenu(new Menu(cit->submenuname()));
+ expand(getMenu(cit->submenuname()),
+ *item.submenu(), buf);
+ tomenu.addWithStatusCheck(item);
+ }
+ break;
+
+ case MenuItem::Separator:
+ tomenu.addWithStatusCheck(*cit);
+ break;
+
+ case MenuItem::Command:
+ if (!specialmenu_.hasFunc(cit->func()))
+ tomenu.addWithStatusCheck(*cit);
+ }
+ }
+
+ // we do not want the menu to end with a separator
+ if (!tomenu.empty()
+ && tomenu.items_.back().kind() == MenuItem::Separator)
+ tomenu.items_.pop_back();
+
+ // Check whether the shortcuts are unique
+ tomenu.checkShortcuts();
+}
+
+
+void Menus::read(Lexer & lex)
+{
+ enum Menutags {
+ md_menu = 1,
+ md_menubar,
+ md_endmenuset,
+ md_last
+ };
+
+ struct keyword_item menutags[md_last - 1] = {
+ { "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;
+ }
+
+ lex.pushTable(menutags, md_last - 1);
+ if (lyxerr.debugging(Debug::PARSER))
+ lex.printTable(lyxerr);
+
+ bool quit = false;
+
+ while (lex.isOK() && !quit) {
+ switch (lex.lex()) {
+ case md_menubar:
+ menubar_.read(lex);
+ break;
+ case md_menu: {
+ lex.next(true);
+ QString const name = toqstr(lex.getDocString());
+ if (hasMenu(name)) {
+ getMenu(name).read(lex);
+ } else {
+ Menu menu(name);
+ menu.read(lex);
+ add(menu);
+ }
+ break;
+ }
+ case md_endmenuset:
+ quit = true;
+ break;
+ default:
+ lex.printError("menubackend::read: "
+ "Unknown menu tag: `$$Token'");
+ break;
+ }
+ }
+ lex.popTable();
+}
+
+
+void Menus::add(Menu const & menu)
+{
+ menulist_.push_back(menu);
+}
+
+
+bool Menus::hasMenu(QString const & name) const
+{
+ return find_if(begin(), end(), MenuNamesEqual(name)) != end();
+}
+
+
+Menu const & Menus::getMenu(QString const & name) const
+{
+ const_iterator cit = find_if(begin(), end(), MenuNamesEqual(name));
+ if (cit == end())
+ lyxerr << "No submenu named " << fromqstr(name) << endl;
+ BOOST_ASSERT(cit != end());
+ return (*cit);
+}
+
+
+Menu & Menus::getMenu(QString const & name)
+{
+ iterator it = find_if(begin(), end(), MenuNamesEqual(name));
+ if (it == end())
+ lyxerr << "No submenu named " << fromqstr(name) << endl;
+ BOOST_ASSERT(it != end());
+ return (*it);
+}
+
+
+Menu const & Menus::getMenubar() const
+{
+ return menubar_;
+}
+
+
} // namespace frontend
} // namespace lyx
#ifndef MENUS_H
#define MENUS_H
-#include "MenuBackend.h"
+#include "FuncStatus.h"
+#include "FuncRequest.h"
#include <QObject>
#include <QHash>
-class QMenu;
+#include <boost/shared_ptr.hpp>
+
+#include <vector>
+class QMenu;
namespace lyx {
+
+class Lexer;
+class Buffer;
+
namespace frontend {
+class Menu;
class GuiView;
class GuiPopupMenu;
class GuiView;
-class Menus : public QObject, public MenuBackend
+///
+class MenuItem {
+public:
+ /// The type of elements that can be in a menu
+ enum Kind {
+ ///
+ Command,
+ ///
+ Submenu,
+ ///
+ Separator,
+ /** This is the list of last opened file,
+ typically for the File menu. */
+ Lastfiles,
+ /** This is the list of opened Documents,
+ typically for the Documents menu. */
+ Documents,
+ /** This is the bookmarks */
+ Bookmarks,
+ ///
+ Toc,
+ /** This is a list of viewable formats
+ typically for the File->View menu. */
+ ViewFormats,
+ /** This is a list of updatable formats
+ typically for the File->Update menu. */
+ UpdateFormats,
+ /** This is a list of exportable formats
+ typically for the File->Export menu. */
+ ExportFormats,
+ /** This is a list of importable formats
+ typically for the File->Export menu. */
+ ImportFormats,
+ /** This is the list of elements available
+ * for insertion into document. */
+ CharStyles,
+ /** This is the list of user-configurable
+ insets to insert into document */
+ Custom,
+ /** This is the list of XML elements to
+ insert into the document */
+ Elements,
+ /** This is the list of floats that we can
+ insert a list for. */
+ FloatListInsert,
+ /** This is the list of floats that we can
+ insert. */
+ FloatInsert,
+ /** This is the list of selections that can
+ be pasted. */
+ PasteRecent,
+ /** toolbars */
+ Toolbars,
+ /** Available branches in document */
+ Branches
+ };
+
+ explicit MenuItem(Kind kind);
+
+ MenuItem(Kind kind,
+ QString const & label,
+ QString const & submenu = QString(),
+ bool optional = false);
+
+ MenuItem(Kind kind,
+ QString const & label,
+ FuncRequest const & func,
+ bool optional = false);
+
+ /// This one is just to please boost::shared_ptr<>
+ ~MenuItem();
+ /// The label of a given menuitem
+ QString label() const;
+ /// The keyboard shortcut (usually underlined in the entry)
+ QString shortcut() const;
+ /// The complete label, with label and shortcut separated by a '|'
+ QString fulllabel() const { return label_;}
+ /// The kind of entry
+ Kind kind() const { return kind_; }
+ /// the action (if relevant)
+ FuncRequest const & func() const { return func_; }
+ /// returns true if the entry should be ommited when disabled
+ bool optional() const { return optional_; }
+ /// returns the status of the lfun associated with this entry
+ FuncStatus const & status() const { return status_; }
+ /// returns the status of the lfun associated with this entry
+ FuncStatus & status() { return status_; }
+ /// returns the status of the lfun associated with this entry
+ void status(FuncStatus const & status) { status_ = status; }
+ ///returns the binding associated to this action.
+ QString binding() const;
+ /// the description of the submenu (if relevant)
+ QString const & submenuname() const { return submenuname_; }
+ /// set the description of the submenu
+ void submenuname(QString const & name) { submenuname_ = name; }
+ ///
+ Menu * submenu() const { return submenu_.get(); }
+ ///
+ void submenu(Menu * menu);
+
+private:
+ ///
+ Kind kind_;
+ ///
+ QString label_;
+ ///
+ FuncRequest func_;
+ ///
+ QString submenuname_;
+ ///
+ bool optional_;
+ ///
+ FuncStatus status_;
+ ///
+ boost::shared_ptr<Menu> submenu_;
+};
+
+
+///
+class Menu {
+public:
+ ///
+ typedef std::vector<MenuItem> ItemList;
+ ///
+ typedef ItemList::const_iterator const_iterator;
+
+ ///
+ explicit Menu(QString const & name = QString()) : name_(name) {}
+
+ /// Add the menu item unconditionally
+ Menu & add(MenuItem const &);
+ /// Checks the associated FuncRequest status before adding the
+ /// menu item.
+ Menu & addWithStatusCheck(MenuItem const &);
+ ///
+ Menu & read(Lexer &);
+ ///
+ QString const & name() const { return name_; }
+ ///
+ bool empty() const { return items_.empty(); }
+ /// Clear the menu content.
+ void clear() { items_.clear(); }
+ ///
+ size_t size() const { return items_.size(); }
+ ///
+ MenuItem const & operator[](size_t) const;
+ ///
+ bool hasFunc(FuncRequest const &) const;
+ ///
+ const_iterator begin() const { return items_.begin(); }
+ ///
+ const_iterator end() const { return items_.end(); }
+
+ // Check whether the menu shortcuts are unique
+ void checkShortcuts() const;
+
+ // search for func in this menu iteratively, and put menu
+ // names in a stack.
+ bool searchMenu(FuncRequest const & func, std::vector<docstring> & names)
+ const;
+
+private:
+ friend class Menus;
+ ///
+ ItemList items_;
+ ///
+ QString name_;
+};
+
+
+class Menus
{
- Q_OBJECT
public:
+ ///
+ typedef std::vector<Menu> MenuList;
+ ///
+ typedef MenuList::const_iterator const_iterator;
+ ///
+ typedef MenuList::iterator iterator;
+
+
Menus() {}
///
/// update the state of the menuitems - not needed
void updateView();
+ ///
+ void read(Lexer &);
+ ///
+ void add(Menu const &);
+ ///
+ bool hasMenu(QString const &) const;
+ ///
+ Menu & getMenu(QString const &);
+ ///
+ Menu const & getMenu(QString const &) const;
+ ///
+ Menu const & getMenubar() const;
+ ///
+ bool empty() const { return menulist_.empty(); }
+ /** 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
+ */
+ void specialMenu(Menu const &);
+ ///
+ Menu const & specialMenu() { return specialmenu_; }
+
+ /// 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
+ */
+ void expand(Menu const & frommenu, Menu & tomenu,
+ Buffer const *) const;
+ ///
+ const_iterator begin() const { return menulist_.begin(); }
+ ///
+ iterator begin() { return menulist_.begin(); }
+ ///
+ const_iterator end() const { return menulist_.end(); }
+ ///
+ iterator end() { return menulist_.end(); }
+
+private:
+ ///
+ MenuList menulist_;
+ ///
+ Menu menubar_;
+ ///
+ Menu specialmenu_;
private:
/// Initialize specific MACOS X menubar