]> git.lyx.org Git - lyx.git/blob - src/MenuBackend.C
Small clean-up.
[lyx.git] / src / MenuBackend.C
1 /**
2  * \file MenuBackend.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Asger Alstrup
7  * \author Lars Gullik Bjønnes
8  * \author Jean-Marc Lasgouttes
9  * \author André Pönitz
10  * \author Dekel Tsur
11  * \author Martin Vermeer
12  *
13  * Full author contact details are available in file CREDITS.
14  */
15
16 #include <config.h>
17
18 #include "MenuBackend.h"
19
20 #include "BranchList.h"
21 #include "buffer.h"
22 #include "bufferlist.h"
23 #include "bufferparams.h"
24 #include "CutAndPaste.h"
25 #include "debug.h"
26 #include "exporter.h"
27 #include "Floating.h"
28 #include "FloatList.h"
29 #include "format.h"
30 #include "gettext.h"
31 #include "importer.h"
32 #include "kbmap.h"
33 #include "lastfiles.h"
34 #include "LyXAction.h"
35 #include "lyx_main.h" // for lastfiles
36 #include "lyxfunc.h"
37 #include "lyxlex.h"
38 #include "toc.h"
39
40 #include "frontends/LyXView.h"
41
42 #include "support/filetools.h"
43 #include "support/lyxfunctional.h"
44 #include "support/lstrings.h"
45 #include "support/tostr.h"
46
47 #include <algorithm>
48
49 using lyx::support::compare_ascii_no_case;
50 using lyx::support::contains;
51 using lyx::support::MakeDisplayPath;
52 using lyx::support::token;
53
54 using std::endl;
55 using std::find_if;
56 using std::max;
57 using std::sort;
58
59 using std::vector;
60
61
62 extern BufferList bufferlist;
63 extern boost::scoped_ptr<kb_keymap> toplevel_keymap;
64
65 // This is the global menu definition
66 MenuBackend menubackend;
67
68
69 MenuItem::MenuItem(Kind kind, string const & label,
70                    string const & command, bool optional)
71         : kind_(kind), label_(label), optional_(optional)
72 {
73         switch (kind) {
74         case Separator:
75         case Documents:
76         case Lastfiles:
77         case Toc:
78         case ViewFormats:
79         case UpdateFormats:
80         case ExportFormats:
81         case ImportFormats:
82         case FloatListInsert:
83         case FloatInsert:
84         case PasteRecent:
85         case Branches:
86                 break;
87         case Command:
88                 action_ = lyxaction.LookupFunc(command);
89
90                 if (action_ == LFUN_UNKNOWN_ACTION) {
91                         lyxerr << "MenuItem(): LyX command `"
92                                << command << "' does not exist." << endl;
93                 }
94                 if (optional_)
95                         lyxerr[Debug::GUI] << "Optional item "
96                                            << command << endl;
97                 break;
98         case Submenu:
99                 submenuname_ = command;
100                 break;
101         }
102 }
103
104
105 MenuItem::MenuItem(Kind kind, string const & label, int action, bool optional)
106         : kind_(kind), label_(label), action_(action), submenuname_(),
107           optional_(optional)
108 {}
109
110
111 MenuItem::~MenuItem()
112 {}
113
114
115 void MenuItem::submenu(Menu * menu)
116 {
117         submenu_.reset(menu);
118 }
119
120
121 string const MenuItem::label() const
122 {
123         return token(label_, '|', 0);
124 }
125
126
127 string const MenuItem::shortcut() const
128 {
129         return token(label_, '|', 1);
130 }
131
132 string const MenuItem::binding() const
133 {
134         if (kind_ != Command)
135                 return string();
136
137         // Get the keys bound to this action, but keep only the
138         // first one later
139         string bindings = toplevel_keymap->findbinding(action_);
140
141         if (!bindings.empty()) {
142                 return bindings.substr(1, bindings.find(']') - 1);
143         } else
144                 return string();
145 }
146
147
148 Menu & Menu::add(MenuItem const & i, LyXView const * view)
149 {
150         if (!view) {
151                 items_.push_back(i);
152                 return *this;
153         }
154
155         switch (i.kind()) {
156         case MenuItem::Command:
157         {
158                 FuncStatus status =
159                         view->getLyXFunc().getStatus(i.action());
160                 if (status.unknown()
161                     || (status.disabled() && i.optional()))
162                         break;
163                 items_.push_back(i);
164                 items_.back().status(status);
165                 break;
166         }
167         case MenuItem::Submenu:
168         {
169                 if (i.submenu()) {
170                         bool disabled = true;
171                         for (const_iterator cit = i.submenu()->begin();
172                              cit != i.submenu()->end(); ++cit) {
173                                 if ((cit->kind() == MenuItem::Command
174                                      || cit->kind() == MenuItem::Submenu)
175                                     && !cit->status().disabled()) {
176                                         disabled = false;
177                                         break;
178                                 }
179                         }
180                         if (!disabled || !i.optional()) {
181                                 items_.push_back(i);
182                                 items_.back().status().disabled(disabled);
183                         }
184                 }
185                 else
186                         items_.push_back(i);
187                 break;
188         }
189         case MenuItem::Separator:
190                 if (!items_.empty()
191                     && items_.back().kind() != MenuItem::Separator)
192                         items_.push_back(i);
193                 break;
194         default:
195                 items_.push_back(i);
196         }
197
198         return *this;
199 }
200
201
202 Menu & Menu::read(LyXLex & lex)
203 {
204         enum Menutags {
205                 md_item = 1,
206                 md_branches,
207                 md_documents,
208                 md_endmenu,
209                 md_exportformats,
210                 md_importformats,
211                 md_lastfiles,
212                 md_optitem,
213                 md_optsubmenu,
214                 md_separator,
215                 md_submenu,
216                 md_toc,
217                 md_updateformats,
218                 md_viewformats,
219                 md_floatlistinsert,
220                 md_floatinsert,
221                 md_pasterecent,
222                 md_last
223         };
224
225         struct keyword_item menutags[md_last - 1] = {
226                 { "branches", md_branches },
227                 { "documents", md_documents },
228                 { "end", md_endmenu },
229                 { "exportformats", md_exportformats },
230                 { "floatinsert", md_floatinsert },
231                 { "floatlistinsert", md_floatlistinsert },
232                 { "importformats", md_importformats },
233                 { "item", md_item },
234                 { "lastfiles", md_lastfiles },
235                 { "optitem", md_optitem },
236                 { "optsubmenu", md_optsubmenu },
237                 { "pasterecent", md_pasterecent },
238                 { "separator", md_separator },
239                 { "submenu", md_submenu },
240                 { "toc", md_toc },
241                 { "updateformats", md_updateformats },
242                 { "viewformats", md_viewformats }
243         };
244
245         lex.pushTable(menutags, md_last - 1);
246         if (lyxerr.debugging(Debug::PARSER))
247                 lex.printTable(lyxerr);
248
249         bool quit = false;
250         bool optional = false;
251
252         while (lex.isOK() && !quit) {
253                 switch (lex.lex()) {
254                 case md_optitem:
255                         optional = true;
256                         // fallback to md_item
257                 case md_item: {
258                         lex.next(true);
259                         string const name = _(lex.getString());
260                         lex.next(true);
261                         string const command = lex.getString();
262                         add(MenuItem(MenuItem::Command, name,
263                                      command, optional));
264                         optional = false;
265                         break;
266                 }
267
268                 case md_separator:
269                         add(MenuItem(MenuItem::Separator));
270                         break;
271
272                 case md_lastfiles:
273                         add(MenuItem(MenuItem::Lastfiles));
274                         break;
275
276                 case md_documents:
277                         add(MenuItem(MenuItem::Documents));
278                         break;
279
280                 case md_toc:
281                         add(MenuItem(MenuItem::Toc));
282                         break;
283
284                 case md_viewformats:
285                         add(MenuItem(MenuItem::ViewFormats));
286                         break;
287
288                 case md_updateformats:
289                         add(MenuItem(MenuItem::UpdateFormats));
290                         break;
291
292                 case md_exportformats:
293                         add(MenuItem(MenuItem::ExportFormats));
294                         break;
295
296                 case md_importformats:
297                         add(MenuItem(MenuItem::ImportFormats));
298                         break;
299
300                 case md_floatlistinsert:
301                         add(MenuItem(MenuItem::FloatListInsert));
302                         break;
303
304                 case md_floatinsert:
305                         add(MenuItem(MenuItem::FloatInsert));
306                         break;
307
308                 case md_pasterecent:
309                         add(MenuItem(MenuItem::PasteRecent));
310                         break;
311
312                 case md_branches:
313                         add(MenuItem(MenuItem::Branches));
314                         break;
315
316                 case md_optsubmenu:
317                         optional = true;
318                         // fallback to md_submenu
319                 case md_submenu: {
320                         lex.next(true);
321                         string const mlabel = _(lex.getString());
322                         lex.next(true);
323                         string const mname = lex.getString();
324                         add(MenuItem(MenuItem::Submenu, mlabel, mname,
325                                      optional));
326                         optional = false;
327                         break;
328                 }
329
330                 case md_endmenu:
331                         quit = true;
332                         break;
333
334                 default:
335                         lex.printError("Menu::read: "
336                                        "Unknown menu tag: `$$Token'");
337                         break;
338                 }
339         }
340         lex.popTable();
341         return *this;
342 }
343
344
345 void Menu::checkShortcuts() const
346 {
347         // This is a quadratic algorithm, but we do not care because
348         // menus are short enough
349         for (const_iterator it1 = begin(); it1 != end(); ++it1) {
350                 string shortcut = it1->shortcut();
351                 if (shortcut.empty())
352                         continue;
353                 if (!contains(it1->label(), shortcut))
354                         lyxerr << "Menu warning: menu entry \""
355                                << it1->label()
356                                << "\" does not contain shortcut `"
357                                << shortcut << "'." << endl;
358                 for (const_iterator it2 = begin(); it2 != it1 ; ++it2) {
359                         if (!compare_ascii_no_case(it2->shortcut(), shortcut)) {
360                                 lyxerr << "Menu warning: menu entries "
361                                        << '"' << it1->fulllabel()
362                                        << "\" and \"" << it2->fulllabel()
363                                        << "\" share the same shortcut."
364                                        << endl;
365                         }
366                 }
367         }
368 }
369
370
371 namespace {
372
373 class compare_format {
374 public:
375         bool operator()(Format const * p1, Format const * p2) {
376                 return *p1 < *p2;
377         }
378 };
379
380 string const limit_string_length(string const & str)
381 {
382         string::size_type const max_item_length = 45;
383
384         if (str.size() > max_item_length)
385                 return str.substr(0, max_item_length - 3) + "...";
386         else
387                 return str;
388 }
389
390
391 void expandLastfiles(Menu & tomenu, LyXView const * view)
392 {
393         int ii = 1;
394         LastFiles::const_iterator lfit = lastfiles->begin();
395         LastFiles::const_iterator end = lastfiles->end();
396
397         for (; lfit != end && ii < 10; ++lfit, ++ii) {
398                 string const label = tostr(ii) + ". "
399                         + MakeDisplayPath((*lfit), 30)
400                         + '|' + tostr(ii);
401                 int const action = lyxaction.
402                         getPseudoAction(LFUN_FILE_OPEN,
403                                         (*lfit));
404                 tomenu.add(MenuItem(MenuItem::Command, label, action), view);
405         }
406 }
407
408 void expandDocuments(Menu & tomenu, LyXView const * view)
409 {
410         typedef vector<string> Strings;
411         Strings const names = bufferlist.getFileNames();
412
413         if (names.empty()) {
414                 tomenu.add(MenuItem(MenuItem::Command, _("No Documents Open!"),
415                                     LFUN_NOACTION), view);
416                 return;
417         }
418
419         int ii = 1;
420         Strings::const_iterator docit = names.begin();
421         Strings::const_iterator end = names.end();
422         for (; docit != end; ++docit, ++ii) {
423                 int const action =
424                         lyxaction.getPseudoAction(LFUN_SWITCHBUFFER, *docit);
425                 string label = MakeDisplayPath(*docit, 20);
426                 if (ii < 10)
427                         label = tostr(ii) + ". " + label + '|' + tostr(ii);
428                 tomenu.add(MenuItem(MenuItem::Command, label, action), view);
429         }
430 }
431
432
433 void expandFormats(MenuItem::Kind kind, Menu & tomenu, LyXView const * view)
434 {
435         if (!view->buffer() && kind != MenuItem::ImportFormats) {
436                 tomenu.add(MenuItem(MenuItem::Command,
437                                     _("No Documents Open!"), LFUN_NOACTION),
438                                     view);
439                 return;
440         }
441
442         typedef vector<Format const *> Formats;
443         Formats formats;
444         kb_action action;
445
446         switch (kind) {
447         case MenuItem::ImportFormats:
448                 formats = Importer::GetImportableFormats();
449                 action = LFUN_IMPORT;
450                 break;
451         case MenuItem::ViewFormats:
452                 formats = Exporter::GetExportableFormats(*view->buffer(), true);
453                 action = LFUN_PREVIEW;
454                 break;
455         case MenuItem::UpdateFormats:
456                 formats = Exporter::GetExportableFormats(*view->buffer(), true);
457                 action = LFUN_UPDATE;
458                 break;
459         default:
460                 formats = Exporter::GetExportableFormats(*view->buffer(), false);
461                 action = LFUN_EXPORT;
462         }
463         sort(formats.begin(), formats.end(), compare_format());
464
465         Formats::const_iterator fit = formats.begin();
466         Formats::const_iterator end = formats.end();
467         for (; fit != end ; ++fit) {
468                 if ((*fit)->dummy())
469                         continue;
470                 string label = (*fit)->prettyname();
471                 // we need to hide the default graphic export formats
472                 // from the external menu, because we need them only
473                 // for the internal lyx-view and external latex run
474                 if (label == "EPS" || label == "XPM" || label == "PNG")
475                         continue;
476
477                 if (kind == MenuItem::ImportFormats) {
478                         if ((*fit)->name() == "text")
479                                 label = _("ASCII text as lines");
480                         else if ((*fit)->name() == "textparagraph")
481                                 label = _("ASCII text as paragraphs");
482                         label += "...";
483                 }
484                 if (!(*fit)->shortcut().empty())
485                         label += '|' + (*fit)->shortcut();
486                 int const action2 = lyxaction.
487                         getPseudoAction(action, (*fit)->name());
488                 tomenu.add(MenuItem(MenuItem::Command, label, action2),
489                            view);
490         }
491 }
492
493
494 void expandFloatListInsert(Menu & tomenu, LyXView const * view)
495 {
496         if (!view->buffer()) {
497                 tomenu.add(MenuItem(MenuItem::Command,
498                                     _("No Documents Open!"), LFUN_NOACTION),
499                            view);
500                 return;
501         }
502
503         FloatList const & floats =
504                 view->buffer()->params().getLyXTextClass().floats();
505         FloatList::const_iterator cit = floats.begin();
506         FloatList::const_iterator end = floats.end();
507         for (; cit != end; ++cit) {
508                 int const action =  lyxaction
509                         .getPseudoAction(LFUN_FLOAT_LIST, cit->second.type());
510                 tomenu.add(MenuItem(MenuItem::Command,
511                                     _(cit->second.listName()), action),
512                            view);
513         }
514 }
515
516
517 void expandFloatInsert(Menu & tomenu, LyXView const * view)
518 {
519         if (!view->buffer()) {
520                 tomenu.add(MenuItem(MenuItem::Command,
521                                     _("No Documents Open!"), LFUN_NOACTION),
522                            view);
523                 return;
524         }
525
526         FloatList const & floats =
527                 view->buffer()->params().getLyXTextClass().floats();
528         FloatList::const_iterator cit = floats.begin();
529         FloatList::const_iterator end = floats.end();
530         for (; cit != end; ++cit) {
531                 // normal float
532                 int const action =
533                         lyxaction.getPseudoAction(LFUN_INSET_FLOAT,
534                                                   cit->second.type());
535                 string const label = _(cit->second.name());
536                 tomenu.add(MenuItem(MenuItem::Command, label, action),
537                            view);
538         }
539 }
540
541
542 Menu::size_type const max_number_of_items = 25;
543
544 void expandToc2(Menu & tomenu,
545                 lyx::toc::Toc const & toc_list,
546                 lyx::toc::Toc::size_type from,
547                 lyx::toc::Toc::size_type to, int depth)
548 {
549         int shortcut_count = 0;
550         if (to - from <= max_number_of_items) {
551                 for (lyx::toc::Toc::size_type i = from; i < to; ++i) {
552                         int const action = toc_list[i].action();
553                         string label(4 * max(0, toc_list[i].depth - depth),' ');
554                         label += limit_string_length(toc_list[i].str);
555                         if (toc_list[i].depth == depth
556                             && ++shortcut_count <= 9) {
557                                 label += '|' + tostr(shortcut_count);
558                         }
559                         tomenu.add(MenuItem(MenuItem::Command, label, action));
560                 }
561         } else {
562                 lyx::toc::Toc::size_type pos = from;
563                 while (pos < to) {
564                         lyx::toc::Toc::size_type new_pos = pos + 1;
565                         while (new_pos < to &&
566                                toc_list[new_pos].depth > depth)
567                                 ++new_pos;
568
569                         int const action = toc_list[pos].action();
570                         string label(4 * max(0, toc_list[pos].depth - depth), ' ');
571                         label += limit_string_length(toc_list[pos].str);
572                         if (toc_list[pos].depth == depth &&
573                             ++shortcut_count <= 9)
574                                 label += '|' + tostr(shortcut_count);
575
576                         if (new_pos == pos + 1) {
577                                 tomenu.add(MenuItem(MenuItem::Command,
578                                                     label, action));
579                         } else {
580                                 MenuItem item(MenuItem::Submenu, label);
581                                 item.submenu(new Menu);
582                                 expandToc2(*item.submenu(),
583                                            toc_list, pos, new_pos, depth + 1);
584                                 tomenu.add(item);
585                         }
586                         pos = new_pos;
587                 }
588         }
589 }
590
591
592 void expandToc(Menu & tomenu, LyXView const * view)
593 {
594         // To make things very cleanly, we would have to pass view to
595         // all MenuItem constructors and to expandToc2. However, we
596         // know that all the entries in a TOC will be have status_ ==
597         // OK, so we avoid this unnecessary overhead (JMarc)
598
599         if (!view->buffer()) {
600                 tomenu.add(MenuItem(MenuItem::Command,
601                                     _("No Documents Open!"), LFUN_NOACTION),
602                            view);
603                 return;
604         }
605
606         lyx::toc::TocList toc_list = lyx::toc::getTocList(*view->buffer());
607         lyx::toc::TocList::const_iterator cit = toc_list.begin();
608         lyx::toc::TocList::const_iterator end = toc_list.end();
609         for (; cit != end; ++cit) {
610                 // Handle this later
611                 if (cit->first == "TOC")
612                         continue;
613
614                 // All the rest is for floats
615                 Menu * menu = new Menu;
616                 lyx::toc::Toc::const_iterator ccit = cit->second.begin();
617                 lyx::toc::Toc::const_iterator eend = cit->second.end();
618                 for (; ccit != eend; ++ccit) {
619                         string const label = limit_string_length(ccit->str);
620                         menu->add(MenuItem(MenuItem::Command,
621                                            label, ccit->action()));
622                 }
623                 string const & floatName = cit->first;
624                 // Is the _(...) really needed here? (Lgb)
625                 MenuItem item(MenuItem::Submenu, _(floatName));
626                 item.submenu(menu);
627                 tomenu.add(item);
628         }
629
630         // Handle normal TOC
631         cit = toc_list.find("TOC");
632         if (cit == end) {
633                 tomenu.add(MenuItem(MenuItem::Command,
634                                     _("No Table of contents")),
635                            view);
636         } else {
637                 expandToc2(tomenu, cit->second, 0, cit->second.size(), 0);
638         }
639 }
640
641
642 void expandPasteRecent(Menu & tomenu, LyXView const * view)
643 {
644         if (!view || !view->buffer())
645                 return;
646
647         vector<string> const selL =
648                 CutAndPaste::availableSelections(*view->buffer());
649
650         vector<string>::const_iterator cit = selL.begin();
651         vector<string>::const_iterator end = selL.end();
652
653         for (unsigned int index = 0; cit != end; ++cit, ++index) {
654                 int const action = lyxaction.getPseudoAction(LFUN_PASTE,
655                                                              tostr(index));
656                 tomenu.add(MenuItem(MenuItem::Command, *cit, action));
657         }
658 }
659
660
661 void expandBranches(Menu & tomenu, LyXView const * view)
662 {
663         if (!view || !view->buffer())
664                 return;
665
666         BufferParams const & params = view->buffer()->params();
667
668         std::list<Branch>::const_iterator cit = params.branchlist().begin();
669         std::list<Branch>::const_iterator end = params.branchlist().end();
670
671         for (int ii = 1; cit != end; ++cit, ++ii) {
672                 string label = cit->getBranch();
673                 int const action = lyxaction.
674                         getPseudoAction(LFUN_INSERT_BRANCH,
675                                         (cit->getBranch()));
676                 if (ii < 10)
677                         label = tostr(ii) + ". " + label + "|" + tostr(ii);
678                 tomenu.add(MenuItem(MenuItem::Command, label, action), view);
679         }
680 }
681
682
683 } // namespace anon
684
685
686 void MenuBackend::expand(Menu const & frommenu, Menu & tomenu,
687                          LyXView const * view) const
688 {
689         for (Menu::const_iterator cit = frommenu.begin();
690              cit != frommenu.end() ; ++cit) {
691                 switch (cit->kind()) {
692                 case MenuItem::Lastfiles:
693                         expandLastfiles(tomenu, view);
694                         break;
695
696                 case MenuItem::Documents:
697                         expandDocuments(tomenu, view);
698                         break;
699
700                 case MenuItem::ImportFormats:
701                 case MenuItem::ViewFormats:
702                 case MenuItem::UpdateFormats:
703                 case MenuItem::ExportFormats:
704                         expandFormats(cit->kind(), tomenu, view);
705                         break;
706
707                 case MenuItem::FloatListInsert:
708                         expandFloatListInsert(tomenu, view);
709                         break;
710
711                 case MenuItem::FloatInsert:
712                         expandFloatInsert(tomenu, view);
713                         break;
714
715                 case MenuItem::PasteRecent:
716                         expandPasteRecent(tomenu, view);
717                         break;
718
719                 case MenuItem::Branches:
720                         expandBranches(tomenu, view);
721                         break;
722
723                 case MenuItem::Toc:
724                         expandToc(tomenu, view);
725                         break;
726
727                 case MenuItem::Submenu: {
728                         MenuItem item(*cit);
729                         item.submenu(new Menu(cit->submenuname()));
730                         expand(getMenu(cit->submenuname()),
731                                *item.submenu(), view);
732                         tomenu.add(item, view);
733                 }
734                 break;
735
736                 default:
737                         tomenu.add(*cit, view);
738                 }
739         }
740
741         // we do not want the menu to end with a separator
742         if (!tomenu.empty()
743             && tomenu.items_.back().kind() == MenuItem::Separator)
744                 tomenu.items_.pop_back();
745
746         // Check whether the shortcuts are unique
747         tomenu.checkShortcuts();
748 }
749
750
751 bool Menu::hasSubmenu(string const & name) const
752 {
753         return find_if(begin(), end(),
754                        lyx::compare_memfun(&MenuItem::submenuname,
755                                            name)) != end();
756 }
757
758
759 void MenuBackend::read(LyXLex & lex)
760 {
761         enum Menutags {
762                 md_menu = 1,
763                 md_menubar,
764                 md_endmenuset,
765                 md_last
766         };
767
768         struct keyword_item menutags[md_last - 1] = {
769                 { "end", md_endmenuset },
770                 { "menu", md_menu },
771                 { "menubar", md_menubar }
772         };
773
774         //consistency check
775         if (compare_ascii_no_case(lex.getString(), "menuset")) {
776                 lyxerr << "Menubackend::read: ERROR wrong token:`"
777                        << lex.getString() << '\'' << endl;
778         }
779
780         lex.pushTable(menutags, md_last - 1);
781         if (lyxerr.debugging(Debug::PARSER))
782                 lex.printTable(lyxerr);
783
784         bool quit = false;
785
786         while (lex.isOK() && !quit) {
787                 switch (lex.lex()) {
788                 case md_menubar:
789                         menubar_.read(lex);
790                         break;
791                 case md_menu: {
792                         lex.next(true);
793                         string const name = lex.getString();
794                         if (hasMenu(name)) {
795                                 getMenu(name).read(lex);
796                         } else {
797                                 Menu menu(name);
798                                 menu.read(lex);
799                                 add(menu);
800                         }
801                         break;
802                 }
803                 case md_endmenuset:
804                         quit = true;
805                         break;
806                 default:
807                         lex.printError("menubackend::read: "
808                                        "Unknown menu tag: `$$Token'");
809                         break;
810                 }
811         }
812         lex.popTable();
813 }
814
815
816 void MenuBackend::add(Menu const & menu)
817 {
818         menulist_.push_back(menu);
819 }
820
821
822 bool MenuBackend::hasMenu(string const & name) const
823 {
824         return find_if(begin(), end(),
825                        lyx::compare_memfun(&Menu::name, name)) != end();
826 }
827
828
829 Menu const & MenuBackend::getMenu(string const & name) const
830 {
831         const_iterator cit = find_if(begin(), end(),
832                                      lyx::compare_memfun(&Menu::name, name));
833         if (cit == end())
834                 lyxerr << "No submenu named " << name << endl;
835         BOOST_ASSERT(cit != end());
836         return (*cit);
837 }
838
839
840 Menu & MenuBackend::getMenu(string const & name)
841 {
842         MenuList::iterator it =
843                 find_if(menulist_.begin(), menulist_.end(),
844                         lyx::compare_memfun(&Menu::name, name));
845         BOOST_ASSERT(it != menulist_.end());
846         return (*it);
847 }
848
849
850 Menu const & MenuBackend::getMenubar() const
851 {
852         return menubar_;
853 }