]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/Menus.cpp
Add dummy context menu when there is non defined.
[lyx.git] / src / frontends / qt4 / Menus.cpp
1 /**
2  * \file qt4/Menus.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author John Levon
7  * \author Asger Alstrup
8  * \author Lars Gullik Bjønnes
9  * \author Jean-Marc Lasgouttes
10  * \author André Pönitz
11  * \author Dekel Tsur
12  * \author Martin Vermeer
13  *
14  * Full author contact details are available in file CREDITS.
15  */
16
17 #include <config.h>
18
19 #include "Menus.h"
20
21 #include "Action.h"
22 #include "GuiApplication.h"
23 #include "GuiView.h"
24 #include "qt_helpers.h"
25
26 #include "BranchList.h"
27 #include "Buffer.h"
28 #include "BufferList.h"
29 #include "BufferParams.h"
30 #include "Converter.h"
31 #include "CutAndPaste.h"
32 #include "Floating.h"
33 #include "FloatList.h"
34 #include "Format.h"
35 #include "FuncRequest.h"
36 #include "FuncStatus.h"
37 #include "KeyMap.h"
38 #include "Lexer.h"
39 #include "LyXAction.h"
40 #include "LyX.h" // for lastfiles
41 #include "LyXFunc.h"
42 #include "Paragraph.h"
43 #include "Session.h"
44 #include "TextClass.h"
45 #include "TocBackend.h"
46 #include "ToolbarBackend.h"
47
48 #include "support/convert.h"
49 #include "support/debug.h"
50 #include "support/filetools.h"
51 #include "support/gettext.h"
52 #include "support/lstrings.h"
53
54 #include <QCursor>
55 #include <QHash>
56 #include <QMenuBar>
57 #include <QString>
58
59 #include <boost/shared_ptr.hpp>
60
61 #include <algorithm>
62 #include <ostream>
63 #include <vector>
64
65 using namespace std;
66 using namespace lyx::support;
67
68
69 namespace lyx {
70 namespace frontend {
71
72 namespace {
73
74 // MacOSX specific stuff is at the end.
75
76 class Menu;
77
78 ///
79 class MenuItem {
80 public:
81         /// The type of elements that can be in a menu
82         enum Kind {
83                 ///
84                 Command,
85                 ///
86                 Submenu,
87                 ///
88                 Separator,
89                 /** This is the list of last opened file,
90                     typically for the File menu. */
91                 Lastfiles,
92                 /** This is the list of opened Documents,
93                     typically for the Documents menu. */
94                 Documents,
95                 /** This is the bookmarks */
96                 Bookmarks,
97                 ///
98                 Toc,
99                 /** This is a list of viewable formats
100                     typically for the File->View menu. */
101                 ViewFormats,
102                 /** This is a list of updatable formats
103                     typically for the File->Update menu. */
104                 UpdateFormats,
105                 /** This is a list of exportable formats
106                     typically for the File->Export menu. */
107                 ExportFormats,
108                 /** This is a list of importable formats
109                     typically for the File->Export menu. */
110                 ImportFormats,
111                 /** This is the list of elements available
112                  * for insertion into document. */
113                 CharStyles,
114                 /** This is the list of user-configurable
115                 insets to insert into document */
116                 Custom,
117                 /** This is the list of XML elements to
118                 insert into the document */
119                 Elements,
120                 /** This is the list of floats that we can
121                     insert a list for. */
122                 FloatListInsert,
123                 /** This is the list of floats that we can
124                     insert. */
125                 FloatInsert,
126                 /** This is the list of selections that can
127                     be pasted. */
128                 PasteRecent,
129                 /** toolbars */
130                 Toolbars,
131                 /** Available branches in document */
132                 Branches
133         };
134
135         explicit MenuItem(Kind kind) : kind_(kind), optional_(false) {}
136
137         MenuItem(Kind kind,
138                  QString const & label,
139                  QString const & submenu = QString(),
140                  bool optional = false)
141                 : kind_(kind), label_(label), submenuname_(submenu), optional_(optional)
142         {
143                 BOOST_ASSERT(kind == Submenu);
144         }
145
146         MenuItem(Kind kind,
147                  QString const & label,
148                  FuncRequest const & func,
149                  bool optional = false)
150                 : kind_(kind), label_(label), func_(func), optional_(optional)
151         {
152                 func_.origin = FuncRequest::MENU;
153         }
154
155         // boost::shared_ptr<Menu> needs this apprently...
156         ~MenuItem() {}
157
158         /// The label of a given menuitem
159         QString label() const { return label_.split('|')[0]; }
160
161         /// The keyboard shortcut (usually underlined in the entry)
162         QString shortcut() const
163         {
164                 return label_.contains('|') ? label_.split('|')[1] : QString();
165         }
166         /// The complete label, with label and shortcut separated by a '|'
167         QString fulllabel() const { return label_;}
168         /// The kind of entry
169         Kind kind() const { return kind_; }
170         /// the action (if relevant)
171         FuncRequest const & func() const { return func_; }
172         /// returns true if the entry should be ommited when disabled
173         bool optional() const { return optional_; }
174         /// returns the status of the lfun associated with this entry
175         FuncStatus const & status() const { return status_; }
176         /// returns the status of the lfun associated with this entry
177         FuncStatus & status() { return status_; }
178         /// returns the status of the lfun associated with this entry
179         void status(FuncStatus const & status) { status_ = status; }
180
181         ///returns the binding associated to this action.
182         QString binding() const
183         {
184                 if (kind_ != Command)
185                         return QString();
186                 // Get the keys bound to this action, but keep only the
187                 // first one later
188                 KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(func_);
189                 if (bindings.size())
190                         return toqstr(bindings.begin()->print(KeySequence::ForGui));
191
192                 LYXERR(Debug::KBMAP, "No binding for "
193                         << lyxaction.getActionName(func_.action)
194                         << '(' << func_.argument() << ')');
195                 return QString();
196         }
197
198         /// the description of the  submenu (if relevant)
199         QString const & submenuname() const { return submenuname_; }
200         /// set the description of the  submenu
201         void submenuname(QString const & name) { submenuname_ = name; }
202         ///
203         Menu * submenu() const { return submenu_.get(); }
204         ///
205         void setSubmenu(Menu * menu) { submenu_.reset(menu); }
206
207 private:
208         ///
209         Kind kind_;
210         ///
211         QString label_;
212         ///
213         FuncRequest func_;
214         ///
215         QString submenuname_;
216         ///
217         bool optional_;
218         ///
219         FuncStatus status_;
220         ///
221         boost::shared_ptr<Menu> submenu_;
222 };
223
224 ///
225 class Menu {
226 public:
227         ///
228         typedef std::vector<MenuItem> ItemList;
229         ///
230         typedef ItemList::const_iterator const_iterator;
231         ///
232         explicit Menu(QString const & name = QString()) : name_(name) {}
233
234         ///
235         void read(Lexer &);
236         ///
237         QString const & name() const { return name_; }
238         ///
239         bool empty() const { return items_.empty(); }
240         /// Clear the menu content.
241         void clear() { items_.clear(); }
242         ///
243         size_t size() const { return items_.size(); }
244         ///
245         MenuItem const & operator[](size_t) const;
246         ///
247         const_iterator begin() const { return items_.begin(); }
248         ///
249         const_iterator end() const { return items_.end(); }
250         
251         // search for func in this menu iteratively, and put menu
252         // names in a stack.
253         bool searchMenu(FuncRequest const & func, std::vector<docstring> & names)
254                 const;
255         ///
256         bool hasFunc(FuncRequest const &) const;
257         /// Add the menu item unconditionally
258         void add(MenuItem const & item) { items_.push_back(item); }
259         /// Checks the associated FuncRequest status before adding the
260         /// menu item.
261         void addWithStatusCheck(MenuItem const &);
262         // Check whether the menu shortcuts are unique
263         void checkShortcuts() const;
264         ///
265         void expandLastfiles();
266         void expandDocuments();
267         void expandBookmarks();
268         void expandFormats(MenuItem::Kind kind, Buffer const * buf);
269         void expandFloatListInsert(Buffer const * buf);
270         void expandFloatInsert(Buffer const * buf);
271         void expandFlexInsert(Buffer const * buf, std::string s);
272         void expandToc2(Toc const & toc_list, size_t from, size_t to, int depth);
273         void expandToc(Buffer const * buf);
274         void expandPasteRecent();
275         void expandToolbars();
276         void expandBranches(Buffer const * buf);
277         ///
278         ItemList items_;
279         ///
280         QString name_;
281 };
282
283 /// a submenu
284 class GuiPopupMenu : public QMenu
285 {
286 public:
287         ///
288         GuiPopupMenu(GuiView * gv, MenuItem const & mi, bool top_level)
289                 : QMenu(gv), top_level_menu(top_level? new Menu : 0), view(gv),
290                 name(mi.submenuname())
291         {
292                 setTitle(label(mi));
293         }
294
295         ///
296         GuiPopupMenu(GuiView * gv, QString const & name_, bool top_level)
297                 : QMenu(gv), top_level_menu(top_level? new Menu : 0), view(gv),
298                 name(name_)
299         {
300                 setTitle(name_);
301         }
302
303         ~GuiPopupMenu() { delete top_level_menu; }
304
305         /// populates the menu or one of its submenu
306         /// This is used as a recursive function
307         void populate(QMenu * qMenu, Menu * menu);
308
309         /// Get a Menu item label from the menu backend
310         QString label(MenuItem const & mi) const;
311
312         void showEvent(QShowEvent * ev)
313         {
314                 if (top_level_menu)
315                         guiApp->menus().updateMenu(name);
316                 QMenu::showEvent(ev);
317         }
318
319         /// Only needed for top level menus.
320         Menu * top_level_menu;
321         /// our owning view
322         GuiView * view;
323         /// the name of this menu
324         QString name;
325 };
326
327 /// Helper for std::find_if
328 class MenuNamesEqual
329 {
330 public:
331         MenuNamesEqual(QString const & name) : name_(name) {}
332         bool operator()(Menu const & menu) const { return menu.name() == name_; }
333 private:
334         QString name_;
335 };
336
337
338 ///
339 typedef std::vector<Menu> MenuList;
340 ///
341 typedef MenuList::const_iterator const_iterator;
342 ///
343 typedef MenuList::iterator iterator;
344
345 /////////////////////////////////////////////////////////////////////
346 // GuiPopupMenu implementation
347 /////////////////////////////////////////////////////////////////////
348
349 void GuiPopupMenu::populate(QMenu * qMenu, Menu * menu)
350 {
351         LYXERR(Debug::GUI, "populating menu " << fromqstr(menu->name()));
352         if (menu->size() == 0) {
353                 LYXERR(Debug::GUI, "\tERROR: empty menu " << fromqstr(menu->name()));
354                 return;
355         }
356         LYXERR(Debug::GUI, " *****  menu entries " << menu->size());
357         Menu::const_iterator m = menu->begin();
358         Menu::const_iterator end = menu->end();
359         for (; m != end; ++m) {
360                 if (m->kind() == MenuItem::Separator)
361                         qMenu->addSeparator();
362                 else if (m->kind() == MenuItem::Submenu) {
363                         QMenu * subMenu = qMenu->addMenu(label(*m));
364                         populate(subMenu, m->submenu());
365                 } else {
366                         // we have a MenuItem::Command
367                         qMenu->addAction(new Action(*view, QIcon(), label(*m), m->func(),
368                                 QString()));
369                 }
370         }
371 }
372
373
374 QString GuiPopupMenu::label(MenuItem const & mi) const
375 {
376         QString label = mi.label();
377         label.replace("&", "&&");
378
379         QString shortcut = mi.shortcut();
380         if (!shortcut.isEmpty()) {
381                 int pos = label.indexOf(shortcut);
382                 if (pos != -1)
383                         //label.insert(pos, 1, char_type('&'));
384                         label.replace(pos, 0, "&");
385         }
386
387         QString const binding = mi.binding();
388         if (!binding.isEmpty())
389                 label += '\t' + binding;
390
391         return label;
392 }
393
394 /////////////////////////////////////////////////////////////////////
395 // Menu implementation
396 /////////////////////////////////////////////////////////////////////
397
398 void Menu::addWithStatusCheck(MenuItem const & i)
399 {
400         switch (i.kind()) {
401
402         case MenuItem::Command: {
403                 FuncStatus status = lyx::getStatus(i.func());
404                 if (status.unknown() || (!status.enabled() && i.optional()))
405                         break;
406                 items_.push_back(i);
407                 items_.back().status(status);
408                 break;
409         }
410
411         case MenuItem::Submenu: {
412                 if (i.submenu()) {
413                         bool enabled = false;
414                         for (const_iterator cit = i.submenu()->begin();
415                              cit != i.submenu()->end(); ++cit) {
416                                 if ((cit->kind() == MenuItem::Command
417                                      || cit->kind() == MenuItem::Submenu)
418                                     && cit->status().enabled()) {
419                                         enabled = true;
420                                         break;
421                                 }
422                         }
423                         if (enabled || !i.optional()) {
424                                 items_.push_back(i);
425                                 items_.back().status().enabled(enabled);
426                         }
427                 }
428                 else
429                         items_.push_back(i);
430                 break;
431         }
432
433         case MenuItem::Separator:
434                 if (!items_.empty() && items_.back().kind() != MenuItem::Separator)
435                         items_.push_back(i);
436                 break;
437
438         default:
439                 items_.push_back(i);
440         }
441 }
442
443
444 void Menu::read(Lexer & lex)
445 {
446         enum Menutags {
447                 md_item = 1,
448                 md_branches,
449                 md_documents,
450                 md_bookmarks,
451                 md_charstyles,
452                 md_custom,
453                 md_elements,
454                 md_endmenu,
455                 md_exportformats,
456                 md_importformats,
457                 md_lastfiles,
458                 md_optitem,
459                 md_optsubmenu,
460                 md_separator,
461                 md_submenu,
462                 md_toc,
463                 md_updateformats,
464                 md_viewformats,
465                 md_floatlistinsert,
466                 md_floatinsert,
467                 md_pasterecent,
468                 md_toolbars,
469                 md_last
470         };
471
472         struct keyword_item menutags[md_last - 1] = {
473                 { "bookmarks", md_bookmarks },
474                 { "branches", md_branches },
475                 { "charstyles", md_charstyles },
476                 { "custom", md_custom },
477                 { "documents", md_documents },
478                 { "elements", md_elements },
479                 { "end", md_endmenu },
480                 { "exportformats", md_exportformats },
481                 { "floatinsert", md_floatinsert },
482                 { "floatlistinsert", md_floatlistinsert },
483                 { "importformats", md_importformats },
484                 { "item", md_item },
485                 { "lastfiles", md_lastfiles },
486                 { "optitem", md_optitem },
487                 { "optsubmenu", md_optsubmenu },
488                 { "pasterecent", md_pasterecent },
489                 { "separator", md_separator },
490                 { "submenu", md_submenu },
491                 { "toc", md_toc },
492                 { "toolbars", md_toolbars },
493                 { "updateformats", md_updateformats },
494                 { "viewformats", md_viewformats }
495         };
496
497         lex.pushTable(menutags, md_last - 1);
498         if (lyxerr.debugging(Debug::PARSER))
499                 lex.printTable(lyxerr);
500
501         bool quit = false;
502         bool optional = false;
503
504         while (lex.isOK() && !quit) {
505                 switch (lex.lex()) {
506                 case md_optitem:
507                         optional = true;
508                         // fallback to md_item
509                 case md_item: {
510                         lex.next(true);
511                         docstring const name = translateIfPossible(lex.getDocString());
512                         lex.next(true);
513                         string const command = lex.getString();
514                         FuncRequest func = lyxaction.lookupFunc(command);
515                         add(MenuItem(MenuItem::Command, toqstr(name), func, optional));
516                         optional = false;
517                         break;
518                 }
519
520                 case md_separator:
521                         add(MenuItem(MenuItem::Separator));
522                         break;
523
524                 case md_lastfiles:
525                         add(MenuItem(MenuItem::Lastfiles));
526                         break;
527
528                 case md_charstyles:
529                         add(MenuItem(MenuItem::CharStyles));
530                         break;
531
532                 case md_custom:
533                         add(MenuItem(MenuItem::Custom));
534                         break;
535
536                 case md_elements:
537                         add(MenuItem(MenuItem::Elements));
538                         break;
539
540                 case md_documents:
541                         add(MenuItem(MenuItem::Documents));
542                         break;
543
544                 case md_bookmarks:
545                         add(MenuItem(MenuItem::Bookmarks));
546                         break;
547
548                 case md_toc:
549                         add(MenuItem(MenuItem::Toc));
550                         break;
551
552                 case md_viewformats:
553                         add(MenuItem(MenuItem::ViewFormats));
554                         break;
555
556                 case md_updateformats:
557                         add(MenuItem(MenuItem::UpdateFormats));
558                         break;
559
560                 case md_exportformats:
561                         add(MenuItem(MenuItem::ExportFormats));
562                         break;
563
564                 case md_importformats:
565                         add(MenuItem(MenuItem::ImportFormats));
566                         break;
567
568                 case md_floatlistinsert:
569                         add(MenuItem(MenuItem::FloatListInsert));
570                         break;
571
572                 case md_floatinsert:
573                         add(MenuItem(MenuItem::FloatInsert));
574                         break;
575
576                 case md_pasterecent:
577                         add(MenuItem(MenuItem::PasteRecent));
578                         break;
579
580                 case md_toolbars:
581                         add(MenuItem(MenuItem::Toolbars));
582                         break;
583
584                 case md_branches:
585                         add(MenuItem(MenuItem::Branches));
586                         break;
587
588                 case md_optsubmenu:
589                         optional = true;
590                         // fallback to md_submenu
591                 case md_submenu: {
592                         lex.next(true);
593                         docstring const mlabel = translateIfPossible(lex.getDocString());
594                         lex.next(true);
595                         docstring const mname = lex.getDocString();
596                         add(MenuItem(MenuItem::Submenu,
597                                 toqstr(mlabel), toqstr(mname), optional));
598                         optional = false;
599                         break;
600                 }
601
602                 case md_endmenu:
603                         quit = true;
604                         break;
605
606                 default:
607                         lex.printError("Menu::read: "
608                                        "Unknown menu tag: `$$Token'");
609                         break;
610                 }
611         }
612         lex.popTable();
613 }
614
615
616 MenuItem const & Menu::operator[](size_type i) const
617 {
618         return items_[i];
619 }
620
621
622 bool Menu::hasFunc(FuncRequest const & func) const
623 {
624         for (const_iterator it = begin(), et = end(); it != et; ++it)
625                 if (it->func() == func)
626                         return true;
627         return false;
628 }
629
630
631 void Menu::checkShortcuts() const
632 {
633         // This is a quadratic algorithm, but we do not care because
634         // menus are short enough
635         for (const_iterator it1 = begin(); it1 != end(); ++it1) {
636                 QString shortcut = it1->shortcut();
637                 if (shortcut.isEmpty())
638                         continue;
639                 if (!it1->label().contains(shortcut))
640                         lyxerr << "Menu warning: menu entry \""
641                                << fromqstr(it1->label())
642                                << "\" does not contain shortcut `"
643                                << fromqstr(shortcut) << "'." << endl;
644                 for (const_iterator it2 = begin(); it2 != it1 ; ++it2) {
645                         if (!it2->shortcut().compare(shortcut, Qt::CaseInsensitive)) {
646                                 lyxerr << "Menu warning: menu entries "
647                                        << '"' << fromqstr(it1->fulllabel())
648                                        << "\" and \"" << fromqstr(it2->fulllabel())
649                                        << "\" share the same shortcut."
650                                        << endl;
651                         }
652                 }
653         }
654 }
655
656
657 bool Menu::searchMenu(FuncRequest const & func, vector<docstring> & names) const
658 {
659         const_iterator m = begin();
660         const_iterator m_end = end();
661         for (; m != m_end; ++m) {
662                 if (m->kind() == MenuItem::Command && m->func() == func) {
663                         names.push_back(qstring_to_ucs4(m->label()));
664                         return true;
665                 }
666                 if (m->kind() == MenuItem::Submenu) {
667                         names.push_back(qstring_to_ucs4(m->label()));
668                         Menu const & submenu = *m->submenu();
669                         if (submenu.searchMenu(func, names))
670                                 return true;
671                         names.pop_back();
672                 }
673         }
674         return false;
675 }
676
677
678 bool compareFormat(Format const * p1, Format const * p2)
679 {
680         return *p1 < *p2;
681 }
682
683
684 QString limitStringLength(docstring const & str)
685 {
686         size_t const max_item_length = 45;
687
688         if (str.size() > max_item_length)
689                 return toqstr(str.substr(0, max_item_length - 3) + "...");
690
691         return toqstr(str);
692 }
693
694
695 void Menu::expandLastfiles()
696 {
697         LastFilesSection::LastFiles const & lf = LyX::cref().session().lastFiles().lastFiles();
698         LastFilesSection::LastFiles::const_iterator lfit = lf.begin();
699
700         int ii = 1;
701
702         for (; lfit != lf.end() && ii < 10; ++lfit, ++ii) {
703                 string const file = lfit->absFilename();
704                 QString const label = QString("%1. %2|%3").arg(ii)
705                         .arg(toqstr(makeDisplayPath(file, 30))).arg(ii);
706                 add(MenuItem(MenuItem::Command, label, FuncRequest(LFUN_FILE_OPEN, file)));
707         }
708 }
709
710
711 void Menu::expandDocuments()
712 {
713         Buffer * first = theBufferList().first();
714         if (first) {
715                 Buffer * b = first;
716                 int ii = 1;
717                 
718                 // We cannot use a for loop as the buffer list cycles.
719                 do {
720                         QString label = toqstr(b->fileName().displayName(20));
721                         if (!b->isClean())
722                                 label += "*";
723                         if (ii < 10)
724                                 label = QString::number(ii) + ". " + label + '|' + QString::number(ii);
725                         add(MenuItem(MenuItem::Command, label,
726                                 FuncRequest(LFUN_BUFFER_SWITCH, b->absFileName())));
727                         
728                         b = theBufferList().next(b);
729                         ++ii;
730                 } while (b != first); 
731         } else {
732                 add(MenuItem(MenuItem::Command, qt_("No Documents Open!"),
733                            FuncRequest(LFUN_NOACTION)));
734         }
735 }
736
737
738 void Menu::expandBookmarks()
739 {
740         lyx::BookmarksSection const & bm = LyX::cref().session().bookmarks();
741
742         for (size_t i = 1; i <= bm.size(); ++i) {
743                 if (bm.isValid(i)) {
744                         string const file = bm.bookmark(i).filename.absFilename();
745                         QString const label = QString("%1. %2|%3").arg(i)
746                                 .arg(toqstr(makeDisplayPath(file, 20))).arg(i);
747                         add(MenuItem(MenuItem::Command, label,
748                                 FuncRequest(LFUN_BOOKMARK_GOTO, convert<docstring>(i))));
749                 }
750         }
751 }
752
753
754 void Menu::expandFormats(MenuItem::Kind kind, Buffer const * buf)
755 {
756         if (!buf && kind != MenuItem::ImportFormats) {
757                 add(MenuItem(MenuItem::Command,
758                                     qt_("No Document Open!"),
759                                     FuncRequest(LFUN_NOACTION)));
760                 return;
761         }
762
763         typedef vector<Format const *> Formats;
764         Formats formats;
765         kb_action action;
766
767         switch (kind) {
768         case MenuItem::ImportFormats:
769                 formats = theConverters().importableFormats();
770                 action = LFUN_BUFFER_IMPORT;
771                 break;
772         case MenuItem::ViewFormats:
773                 formats = buf->exportableFormats(true);
774                 action = LFUN_BUFFER_VIEW;
775                 break;
776         case MenuItem::UpdateFormats:
777                 formats = buf->exportableFormats(true);
778                 action = LFUN_BUFFER_UPDATE;
779                 break;
780         default:
781                 formats = buf->exportableFormats(false);
782                 action = LFUN_BUFFER_EXPORT;
783         }
784         sort(formats.begin(), formats.end(), &compareFormat);
785
786         Formats::const_iterator fit = formats.begin();
787         Formats::const_iterator end = formats.end();
788         for (; fit != end ; ++fit) {
789                 if ((*fit)->dummy())
790                         continue;
791                 QString label = toqstr((*fit)->prettyname());
792                 QString const shortcut = toqstr((*fit)->shortcut());
793
794                 switch (kind) {
795                 case MenuItem::ImportFormats:
796                         // FIXME: This is a hack, we should rather solve
797                         // FIXME: bug 2488 instead.
798                         if ((*fit)->name() == "text")
799                                 label = qt_("Plain Text");
800                         else if ((*fit)->name() == "textparagraph")
801                                 label = qt_("Plain Text, Join Lines");
802                         label += "...";
803                         break;
804                 case MenuItem::ViewFormats:
805                 case MenuItem::ExportFormats:
806                 case MenuItem::UpdateFormats:
807                         if (!(*fit)->documentFormat())
808                                 continue;
809                         break;
810                 default:
811                         BOOST_ASSERT(false);
812                         break;
813                 }
814                 // FIXME: if we had proper support for translating the
815                 // format names defined in configure.py, there would
816                 // not be a need to check whether the shortcut is
817                 // correct. If we add it uncondiitonally, it would
818                 // create useless warnings on bad shortcuts
819                 if (!shortcut.isEmpty() && label.contains(shortcut))
820                         label += '|' + shortcut;
821
822                 if (buf)
823                         addWithStatusCheck(MenuItem(MenuItem::Command, label,
824                                 FuncRequest(action, (*fit)->name())));
825                 else
826                         add(MenuItem(MenuItem::Command, label,
827                                 FuncRequest(action, (*fit)->name())));
828         }
829 }
830
831
832 void Menu::expandFloatListInsert(Buffer const * buf)
833 {
834         if (!buf) {
835                 add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
836                                     FuncRequest(LFUN_NOACTION)));
837                 return;
838         }
839
840         FloatList const & floats = buf->params().documentClass().floats();
841         FloatList::const_iterator cit = floats.begin();
842         FloatList::const_iterator end = floats.end();
843         for (; cit != end; ++cit) {
844                 addWithStatusCheck(MenuItem(MenuItem::Command,
845                                     qt_(cit->second.listName()),
846                                     FuncRequest(LFUN_FLOAT_LIST,
847                                                 cit->second.type())));
848         }
849 }
850
851
852 void Menu::expandFloatInsert(Buffer const * buf)
853 {
854         if (!buf) {
855                 add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
856                                     FuncRequest(LFUN_NOACTION)));
857                 return;
858         }
859
860         FloatList const & floats = buf->params().documentClass().floats();
861         FloatList::const_iterator cit = floats.begin();
862         FloatList::const_iterator end = floats.end();
863         for (; cit != end; ++cit) {
864                 // normal float
865                 QString const label = qt_(cit->second.name());
866                 addWithStatusCheck(MenuItem(MenuItem::Command, label,
867                                     FuncRequest(LFUN_FLOAT_INSERT,
868                                                 cit->second.type())));
869         }
870 }
871
872
873 void Menu::expandFlexInsert(Buffer const * buf, string s)
874 {
875         if (!buf) {
876                 add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
877                                     FuncRequest(LFUN_NOACTION)));
878                 return;
879         }
880         TextClass::InsetLayouts const & insetLayouts =
881                 buf->params().documentClass().insetLayouts();
882         TextClass::InsetLayouts::const_iterator cit = insetLayouts.begin();
883         TextClass::InsetLayouts::const_iterator end = insetLayouts.end();
884         for (; cit != end; ++cit) {
885                 docstring const label = cit->first;
886                 if (cit->second.lyxtype() == s)
887                         addWithStatusCheck(MenuItem(MenuItem::Command, 
888                                 toqstr(label), FuncRequest(LFUN_FLEX_INSERT,
889                                                 label)));
890         }
891 }
892
893
894 size_t const max_number_of_items = 25;
895
896 void Menu::expandToc2(Toc const & toc_list,
897                 size_t from, size_t to, int depth)
898 {
899         int shortcut_count = 0;
900
901         // check whether depth is smaller than the smallest depth in toc.
902         int min_depth = 1000;
903         for (size_t i = from; i < to; ++i)
904                 min_depth = min(min_depth, toc_list[i].depth());
905         if (min_depth > depth)
906                 depth = min_depth;
907
908         if (to - from <= max_number_of_items) {
909                 for (size_t i = from; i < to; ++i) {
910                         QString label(4 * max(0, toc_list[i].depth() - depth), ' ');
911                         label += limitStringLength(toc_list[i].str());
912                         if (toc_list[i].depth() == depth
913                             && shortcut_count < 9) {
914                                 if (label.contains(QString::number(shortcut_count + 1)))
915                                         label += '|' + QString::number(++shortcut_count);
916                         }
917                         add(MenuItem(MenuItem::Command, label,
918                                             FuncRequest(toc_list[i].action())));
919                 }
920         } else {
921                 size_t pos = from;
922                 while (pos < to) {
923                         size_t new_pos = pos + 1;
924                         while (new_pos < to &&
925                                toc_list[new_pos].depth() > depth)
926                                 ++new_pos;
927
928                         QString label(4 * max(0, toc_list[pos].depth() - depth), ' ');
929                         label += limitStringLength(toc_list[pos].str());
930                         if (toc_list[pos].depth() == depth &&
931                             shortcut_count < 9) {
932                                 if (label.contains(QString::number(shortcut_count + 1)))
933                                         label += '|' + QString::number(++shortcut_count);
934                         }
935                         if (new_pos == pos + 1) {
936                                 add(MenuItem(MenuItem::Command,
937                                                     label, FuncRequest(toc_list[pos].action())));
938                         } else {
939                                 MenuItem item(MenuItem::Submenu, label);
940                                 item.setSubmenu(new Menu);
941                                 item.submenu()->expandToc2(toc_list, pos, new_pos, depth + 1);
942                                 add(item);
943                         }
944                         pos = new_pos;
945                 }
946         }
947 }
948
949
950 void Menu::expandToc(Buffer const * buf)
951 {
952         // To make things very cleanly, we would have to pass buf to
953         // all MenuItem constructors and to expandToc2. However, we
954         // know that all the entries in a TOC will be have status_ ==
955         // OK, so we avoid this unnecessary overhead (JMarc)
956
957         if (!buf) {
958                 add(MenuItem(MenuItem::Command, qt_("No Document Open!"),
959                                     FuncRequest(LFUN_NOACTION)));
960                 return;
961         }
962
963         Buffer* cbuf = const_cast<Buffer*>(buf);
964         cbuf->tocBackend().update();
965         cbuf->structureChanged();
966
967         // Add an entry for the master doc if this is a child doc
968         Buffer const * const master = buf->masterBuffer();
969         if (buf != master) {
970                 ParIterator const pit = par_iterator_begin(master->inset());
971                 string const arg = convert<string>(pit->id());
972                 FuncRequest f(LFUN_PARAGRAPH_GOTO, arg);
973                 add(MenuItem(MenuItem::Command, qt_("Master Document"), f));
974         }
975
976         FloatList const & floatlist = buf->params().documentClass().floats();
977         TocList const & toc_list = buf->tocBackend().tocs();
978         TocList::const_iterator cit = toc_list.begin();
979         TocList::const_iterator end = toc_list.end();
980         for (; cit != end; ++cit) {
981                 // Handle this later
982                 if (cit->first == "tableofcontents")
983                         continue;
984
985                 // All the rest is for floats
986                 Menu * submenu = new Menu;
987                 TocIterator ccit = cit->second.begin();
988                 TocIterator eend = cit->second.end();
989                 for (; ccit != eend; ++ccit) {
990                         QString const label = limitStringLength(ccit->str());
991                         submenu->add(MenuItem(MenuItem::Command, label,
992                                            FuncRequest(ccit->action())));
993                 }
994                 string const & floatName = floatlist.getType(cit->first).listName();
995                 QString label;
996                 if (!floatName.empty())
997                         label = qt_(floatName);
998                 // BUG3633: listings is not a proper float so its name
999                 // is not shown in floatlist.
1000                 else if (cit->first == "equation")
1001                         label = qt_("List of Equations");
1002                 else if (cit->first == "index")
1003                         label = qt_("List of Indexes");
1004                 else if (cit->first == "listing")
1005                         label = qt_("List of Listings");
1006                 else if (cit->first == "marginalnote")
1007                         label = qt_("List of Marginal notes");
1008                 else if (cit->first == "note")
1009                         label = qt_("List of Notes");
1010                 else if (cit->first == "footnote")
1011                         label = qt_("List of Foot notes");
1012                 else if (cit->first == "label")
1013                         label = qt_("Labels and References");
1014                 else if (cit->first == "citation")
1015                         label = qt_("List of Citations");
1016                 // this should not happen now, but if something else like
1017                 // listings is added later, this can avoid an empty menu name.
1018                 else
1019                         label = qt_("Other floats");
1020                 MenuItem item(MenuItem::Submenu, label);
1021                 item.setSubmenu(submenu);
1022                 add(item);
1023         }
1024
1025         // Handle normal TOC
1026         cit = toc_list.find("tableofcontents");
1027         if (cit == end) {
1028                 addWithStatusCheck(MenuItem(MenuItem::Command,
1029                                     qt_("No Table of contents"),
1030                                     FuncRequest()));
1031         } else {
1032                 expandToc2(cit->second, 0, cit->second.size(), 0);
1033         }
1034 }
1035
1036
1037 void Menu::expandPasteRecent()
1038 {
1039         vector<docstring> const sel = cap::availableSelections();
1040
1041         vector<docstring>::const_iterator cit = sel.begin();
1042         vector<docstring>::const_iterator end = sel.end();
1043
1044         for (unsigned int index = 0; cit != end; ++cit, ++index) {
1045                 add(MenuItem(MenuItem::Command, toqstr(*cit),
1046                                     FuncRequest(LFUN_PASTE, convert<string>(index))));
1047         }
1048 }
1049
1050
1051 void Menu::expandToolbars()
1052 {
1053         //
1054         // extracts the toolbars from the backend
1055         ToolbarBackend::Toolbars::const_iterator cit = toolbarbackend.begin();
1056         ToolbarBackend::Toolbars::const_iterator end = toolbarbackend.end();
1057
1058         for (; cit != end; ++cit) {
1059                 QString label = qt_(cit->gui_name);
1060                 // frontends are not supposed to turn on/off toolbars,
1061                 // if they cannot update ToolbarBackend::flags. That
1062                 // is to say, ToolbarsBackend::flags should reflect
1063                 // the true state of toolbars.
1064                 //
1065                 // menu is displayed as
1066                 //       on/off review
1067                 // and
1068                 //              review (auto)
1069                 // in the case of auto.
1070                 if (cit->flags & ToolbarInfo::AUTO)
1071                         label += qt_(" (auto)");
1072                 add(MenuItem(MenuItem::Command, label,
1073                                     FuncRequest(LFUN_TOOLBAR_TOGGLE, cit->name + " allowauto")));
1074         }
1075 }
1076
1077
1078 void Menu::expandBranches(Buffer const * buf)
1079 {
1080         if (!buf) {
1081                 add(MenuItem(MenuItem::Command,
1082                                     qt_("No Document Open!"),
1083                                     FuncRequest(LFUN_NOACTION)));
1084                 return;
1085         }
1086
1087         BufferParams const & params = buf->masterBuffer()->params();
1088         if (params.branchlist().empty()) {
1089                 add(MenuItem(MenuItem::Command,
1090                                     qt_("No Branch in Document!"),
1091                                     FuncRequest(LFUN_NOACTION)));
1092                 return;
1093         }
1094
1095         BranchList::const_iterator cit = params.branchlist().begin();
1096         BranchList::const_iterator end = params.branchlist().end();
1097
1098         for (int ii = 1; cit != end; ++cit, ++ii) {
1099                 docstring label = cit->getBranch();
1100                 if (ii < 10)
1101                         label = convert<docstring>(ii) + ". " + label + char_type('|') + convert<docstring>(ii);
1102                 addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(label),
1103                                     FuncRequest(LFUN_BRANCH_INSERT,
1104                                                 cit->getBranch())));
1105         }
1106 }
1107
1108 } // namespace anon
1109
1110
1111 struct Menus::Impl {
1112         ///
1113         bool hasMenu(QString const &) const;
1114         ///
1115         Menu & getMenu(QString const &);
1116         ///
1117         Menu const & getMenu(QString const &) const;
1118
1119         /// Expands some special entries of the menu
1120         /** The entries with the following kind are expanded to a
1121             sequence of Command MenuItems: Lastfiles, Documents,
1122             ViewFormats, ExportFormats, UpdateFormats, Branches
1123         */
1124         void expand(Menu const & frommenu, Menu & tomenu,
1125                     Buffer const *) const;
1126
1127         /// Initialize specific MACOS X menubar
1128         void macxMenuBarInit(GuiView * view);
1129
1130         /// Mac special menu.
1131         /** This defines a menu whose entries list the FuncRequests
1132             that will be removed by expand() in other menus. This is
1133             used by the Qt/Mac code
1134         */
1135         Menu specialmenu_;
1136
1137         ///
1138         MenuList menulist_;
1139         ///
1140         Menu menubar_;
1141
1142         typedef QHash<QString, GuiPopupMenu *> NameMap;
1143
1144         /// name to menu for \c menu() method.
1145         NameMap name_map_;
1146 };
1147
1148
1149 /////////////////////////////////////////////////////////////////////
1150 // Menus::Impl implementation
1151 /////////////////////////////////////////////////////////////////////
1152
1153 /*
1154   Here is what the Qt documentation says about how a menubar is chosen:
1155
1156      1) If the window has a QMenuBar then it is used. 2) If the window
1157      is a modal then its menubar is used. If no menubar is specified
1158      then a default menubar is used (as documented below) 3) If the
1159      window has no parent then the default menubar is used (as
1160      documented below).
1161
1162      The above 3 steps are applied all the way up the parent window
1163      chain until one of the above are satisifed. If all else fails a
1164      default menubar will be created, the default menubar on Qt/Mac is
1165      an empty menubar, however you can create a different default
1166      menubar by creating a parentless QMenuBar, the first one created
1167      will thus be designated the default menubar, and will be used
1168      whenever a default menubar is needed.
1169
1170   Thus, for Qt/Mac, we add the menus to a free standing menubar, so
1171   that this menubar will be used also when one of LyX' dialogs has
1172   focus. (JMarc)
1173 */
1174 void Menus::Impl::macxMenuBarInit(GuiView * view)
1175 {
1176         // The Mac menubar initialisation must be done only once!
1177         static bool done = false;
1178         if (done)
1179                 return;
1180         done = true;
1181
1182         /* Since Qt 4.2, the qt/mac menu code has special code for
1183            specifying the role of a menu entry. However, it does not
1184            work very well with our scheme of creating menus on demand,
1185            and therefore we need to put these entries in a special
1186            invisible menu. (JMarc)
1187         */
1188
1189         /* The entries of our special mac menu. If we add support for
1190          * special entries in Menus, we could imagine something
1191          * like
1192          *    SpecialItem About " "About LyX" "dialog-show aboutlyx"
1193          * and therefore avoid hardcoding. I am not sure it is worth
1194          * the hassle, though. (JMarc)
1195          */
1196         struct MacMenuEntry {
1197                 kb_action action;
1198                 char const * arg;
1199                 char const * label;
1200                 QAction::MenuRole role;
1201         };
1202
1203         MacMenuEntry entries[] = {
1204                 {LFUN_DIALOG_SHOW, "aboutlyx", "About LyX",
1205                  QAction::AboutRole},
1206                 {LFUN_DIALOG_SHOW, "prefs", "Preferences",
1207                  QAction::PreferencesRole},
1208                 {LFUN_RECONFIGURE, "", "Reconfigure",
1209                  QAction::ApplicationSpecificRole},
1210                 {LFUN_LYX_QUIT, "", "Quit LyX", QAction::QuitRole}
1211         };
1212         const size_t num_entries = sizeof(entries) / sizeof(entries[0]);
1213
1214         // the special menu for Menus.
1215         for (size_t i = 0 ; i < num_entries ; ++i) {
1216                 FuncRequest const func(entries[i].action,
1217                                        from_utf8(entries[i].arg));
1218                 specialmenu_.add(MenuItem(MenuItem::Command, entries[i].label, func));
1219         }
1220
1221         // add the entries to a QMenu that will eventually be empty
1222         // and therefore invisible.
1223         QMenu * qMenu = view->menuBar()->addMenu("special");
1224         Menu::const_iterator cit = specialmenu_.begin();
1225         Menu::const_iterator end = specialmenu_.end();
1226         for (size_t i = 0 ; cit != end ; ++cit, ++i) {
1227                 Action * action = new Action(*view, QIcon(), cit->label(),
1228                                              cit->func(), QString());
1229                 action->setMenuRole(entries[i].role);
1230                 qMenu->addAction(action);
1231         }
1232 }
1233
1234
1235 void Menus::Impl::expand(Menu const & frommenu, Menu & tomenu,
1236                          Buffer const * buf) const
1237 {
1238         if (!tomenu.empty())
1239                 tomenu.clear();
1240
1241         for (Menu::const_iterator cit = frommenu.begin();
1242              cit != frommenu.end() ; ++cit) {
1243                 switch (cit->kind()) {
1244                 case MenuItem::Lastfiles:
1245                         tomenu.expandLastfiles();
1246                         break;
1247
1248                 case MenuItem::Documents:
1249                         tomenu.expandDocuments();
1250                         break;
1251
1252                 case MenuItem::Bookmarks:
1253                         tomenu.expandBookmarks();
1254                         break;
1255
1256                 case MenuItem::ImportFormats:
1257                 case MenuItem::ViewFormats:
1258                 case MenuItem::UpdateFormats:
1259                 case MenuItem::ExportFormats:
1260                         tomenu.expandFormats(cit->kind(), buf);
1261                         break;
1262
1263                 case MenuItem::CharStyles:
1264                         tomenu.expandFlexInsert(buf, "charstyle");
1265                         break;
1266
1267                 case MenuItem::Custom:
1268                         tomenu.expandFlexInsert(buf, "custom");
1269                         break;
1270
1271                 case MenuItem::Elements:
1272                         tomenu.expandFlexInsert(buf, "element");
1273                         break;
1274
1275                 case MenuItem::FloatListInsert:
1276                         tomenu.expandFloatListInsert(buf);
1277                         break;
1278
1279                 case MenuItem::FloatInsert:
1280                         tomenu.expandFloatInsert(buf);
1281                         break;
1282
1283                 case MenuItem::PasteRecent:
1284                         tomenu.expandPasteRecent();
1285                         break;
1286
1287                 case MenuItem::Toolbars:
1288                         tomenu.expandToolbars();
1289                         break;
1290
1291                 case MenuItem::Branches:
1292                         tomenu.expandBranches(buf);
1293                         break;
1294
1295                 case MenuItem::Toc:
1296                         tomenu.expandToc(buf);
1297                         break;
1298
1299                 case MenuItem::Submenu: {
1300                         MenuItem item(*cit);
1301                         item.setSubmenu(new Menu(cit->submenuname()));
1302                         expand(getMenu(cit->submenuname()), *item.submenu(), buf);
1303                         tomenu.addWithStatusCheck(item);
1304                 }
1305                 break;
1306
1307                 case MenuItem::Separator:
1308                         tomenu.addWithStatusCheck(*cit);
1309                         break;
1310
1311                 case MenuItem::Command:
1312                         if (!specialmenu_.hasFunc(cit->func()))
1313                                 tomenu.addWithStatusCheck(*cit);
1314                 }
1315         }
1316
1317         // we do not want the menu to end with a separator
1318         if (!tomenu.empty() && tomenu.items_.back().kind() == MenuItem::Separator)
1319                 tomenu.items_.pop_back();
1320
1321         // Check whether the shortcuts are unique
1322         tomenu.checkShortcuts();
1323 }
1324
1325
1326 bool Menus::Impl::hasMenu(QString const & name) const
1327 {
1328         return find_if(menulist_.begin(), menulist_.end(),
1329                 MenuNamesEqual(name)) != menulist_.end();
1330 }
1331
1332
1333 Menu const & Menus::Impl::getMenu(QString const & name) const
1334 {
1335         const_iterator cit = find_if(menulist_.begin(), menulist_.end(),
1336                 MenuNamesEqual(name));
1337         if (cit == menulist_.end())
1338                 lyxerr << "No submenu named " << fromqstr(name) << endl;
1339         BOOST_ASSERT(cit != menulist_.end());
1340         return (*cit);
1341 }
1342
1343
1344 Menu & Menus::Impl::getMenu(QString const & name)
1345 {
1346         iterator it = find_if(menulist_.begin(), menulist_.end(),
1347                 MenuNamesEqual(name));
1348         if (it == menulist_.end())
1349                 lyxerr << "No submenu named " << fromqstr(name) << endl;
1350         BOOST_ASSERT(it != menulist_.end());
1351         return (*it);
1352 }
1353
1354 /////////////////////////////////////////////////////////////////////
1355 // Menus implementation
1356 /////////////////////////////////////////////////////////////////////
1357
1358 Menus::Menus(): d(new Impl) {}
1359
1360
1361 void Menus::read(Lexer & lex)
1362 {
1363         enum Menutags {
1364                 md_menu = 1,
1365                 md_menubar,
1366                 md_endmenuset,
1367                 md_last
1368         };
1369
1370         struct keyword_item menutags[md_last - 1] = {
1371                 { "end", md_endmenuset },
1372                 { "menu", md_menu },
1373                 { "menubar", md_menubar }
1374         };
1375
1376         //consistency check
1377         if (compare_ascii_no_case(lex.getString(), "menuset")) {
1378                 lyxerr << "Menubackend::read: ERROR wrong token:`"
1379                        << lex.getString() << '\'' << endl;
1380         }
1381
1382         lex.pushTable(menutags, md_last - 1);
1383         if (lyxerr.debugging(Debug::PARSER))
1384                 lex.printTable(lyxerr);
1385
1386         bool quit = false;
1387
1388         while (lex.isOK() && !quit) {
1389                 switch (lex.lex()) {
1390                 case md_menubar:
1391                         d->menubar_.read(lex);
1392                         break;
1393                 case md_menu: {
1394                         lex.next(true);
1395                         QString const name = toqstr(lex.getDocString());
1396                         if (d->hasMenu(name))
1397                                 d->getMenu(name).read(lex);
1398                         else {
1399                                 Menu menu(name);
1400                                 menu.read(lex);
1401                                 d->menulist_.push_back(menu);
1402                         }
1403                         break;
1404                 }
1405                 case md_endmenuset:
1406                         quit = true;
1407                         break;
1408                 default:
1409                         lex.printError("menubackend::read: "
1410                                        "Unknown menu tag: `$$Token'");
1411                         break;
1412                 }
1413         }
1414         lex.popTable();
1415 }
1416
1417
1418 bool Menus::searchMenu(FuncRequest const & func,
1419         vector<docstring> & names) const
1420 {
1421         return d->menubar_.searchMenu(func, names);
1422 }
1423
1424
1425 void Menus::fillMenuBar(GuiView * view)
1426 {
1427         // Clear all menubar contents before filling it.
1428         view->menuBar()->clear();
1429         
1430 #ifdef Q_WS_MACX
1431         // setup special mac specific menu item
1432         d->macxMenuBarInit(view);
1433 #endif
1434
1435         LYXERR(Debug::GUI, "populating menu bar" << fromqstr(d->menubar_.name()));
1436
1437         if (d->menubar_.size() == 0) {
1438                 LYXERR(Debug::GUI, "\tERROR: empty menu bar"
1439                         << fromqstr(d->menubar_.name()));
1440                 return;
1441         }
1442         else {
1443                 LYXERR(Debug::GUI, "menu bar entries "
1444                         << d->menubar_.size());
1445         }
1446
1447         Menu menu;
1448         d->expand(d->menubar_, menu, view->buffer());
1449
1450         Menu::const_iterator m = menu.begin();
1451         Menu::const_iterator end = menu.end();
1452
1453         for (; m != end; ++m) {
1454
1455                 if (m->kind() != MenuItem::Submenu) {
1456                         LYXERR(Debug::GUI, "\tERROR: not a submenu " << fromqstr(m->label()));
1457                         continue;
1458                 }
1459
1460                 LYXERR(Debug::GUI, "menu bar item " << fromqstr(m->label())
1461                         << " is a submenu named " << fromqstr(m->submenuname()));
1462
1463                 QString name = m->submenuname();
1464                 if (!d->hasMenu(name)) {
1465                         LYXERR(Debug::GUI, "\tERROR: " << fromqstr(name)
1466                                 << " submenu has no menu!");
1467                         continue;
1468                 }
1469
1470                 GuiPopupMenu * qmenu = new GuiPopupMenu(view, *m, true);
1471                 view->menuBar()->addMenu(qmenu);
1472
1473                 d->name_map_[name] = qmenu;
1474         }
1475 }
1476
1477
1478 void Menus::updateMenu(QString const & name)
1479 {
1480         GuiPopupMenu * qmenu = d->name_map_[name];
1481         LYXERR(Debug::GUI, "GuiPopupMenu::updateView()"
1482                 << "\tTriggered menu: " << fromqstr(qmenu->name));
1483         qmenu->clear();
1484
1485         if (qmenu->name.isEmpty())
1486                 return;
1487
1488         // Here, We make sure that theLyXFunc points to the correct LyXView.
1489         theLyXFunc().setLyXView(qmenu->view);
1490
1491         if (!d->hasMenu(qmenu->name)) {
1492                 qmenu->addAction(qt_("No action defined!"));
1493                 LYXERR(Debug::GUI, "\tWARNING: non existing menu: "
1494                         << fromqstr(qmenu->name));
1495                 return;
1496         }
1497
1498         Menu const & fromLyxMenu = d->getMenu(qmenu->name);
1499         d->expand(fromLyxMenu, *qmenu->top_level_menu, qmenu->view->buffer());
1500         qmenu->populate(qmenu, qmenu->top_level_menu);
1501 }
1502
1503
1504 QMenu * Menus::menu(QString const & name, GuiView & view)
1505 {
1506         LYXERR(Debug::GUI, "Context menu requested: " << fromqstr(name));
1507         GuiPopupMenu * menu = d->name_map_.value(name, 0);
1508         if (!menu && !name.startsWith("context-")) {
1509                 LYXERR0("resquested context menu not found: " << fromqstr(name));
1510                 return 0;
1511         }
1512
1513         menu = new GuiPopupMenu(&view, name, true);
1514         d->name_map_[name] = menu;
1515         return menu;
1516 }
1517
1518 } // namespace frontend
1519 } // namespace lyx
1520
1521 #include "Menus_moc.cpp"