3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
7 * \author Asger Alstrup
8 * \author Lars Gullik Bjønnes
9 * \author Jean-Marc Lasgouttes
10 * \author André Pönitz
12 * \author Martin Vermeer
14 * Full author contact details are available in file CREDITS.
22 #include "GuiApplication.h"
24 #include "qt_helpers.h"
26 #include "BiblioInfo.h"
27 #include "BranchList.h"
29 #include "BufferList.h"
30 #include "BufferParams.h"
31 #include "BufferView.h"
32 #include "Converter.h"
33 #include "CutAndPaste.h"
35 #include "FloatList.h"
37 #include "FuncRequest.h"
38 #include "FuncStatus.h"
39 #include "IndicesList.h"
42 #include "LyXAction.h"
43 #include "LyX.h" // for lastfiles
46 #include "Paragraph.h"
47 #include "ParIterator.h"
49 #include "TextClass.h"
50 #include "TocBackend.h"
52 #include "WordLangTuple.h"
54 #include "insets/Inset.h"
55 #include "insets/InsetCitation.h"
56 #include "insets/InsetGraphics.h"
58 #include "support/lassert.h"
59 #include "support/convert.h"
60 #include "support/debug.h"
61 #include "support/docstring_list.h"
62 #include "support/filetools.h"
63 #include "support/gettext.h"
64 #include "support/lstrings.h"
72 #include <boost/shared_ptr.hpp>
78 using namespace lyx::support
;
86 // MacOSX specific stuff is at the end.
93 /// The type of elements that can be in a menu
101 /** This type of item explains why something is unavailable. If this
102 menuitem is in a submenu, the submenu is enabled to make sure the
103 user sees the information. */
105 /** This type of item merely shows that there might be a list or
106 something alike at this position, but the list is still empty.
107 If this item is in a submenu, the submenu will not always be
110 /** This is the list of last opened file,
111 typically for the File menu. */
113 /** This is the list of opened Documents,
114 typically for the Documents menu. */
116 /** This is the bookmarks */
120 /** This is a list of viewable formats
121 typically for the File->View menu. */
123 /** This is a list of updatable formats
124 typically for the File->Update menu. */
126 /** This is a list of exportable formats
127 typically for the File->Export menu. */
129 /** This is a list of importable formats
130 typically for the File->Export menu. */
132 /** This is the list of elements available
133 * for insertion into document. */
135 /** This is the list of user-configurable
136 insets to insert into document */
138 /** This is the list of XML elements to
139 insert into the document */
141 /** This is the list of floats that we can
142 insert a list for. */
144 /** This is the list of floats that we can
147 /** This is the list of selections that can
152 /** Available branches in document */
154 /** Available indices in document */
156 /** Context menu for indices in document */
158 /** Available index lists in document */
160 /** Context menu for available indices lists in document */
162 /** Available citation styles for a given citation */
164 /** Available graphics groups */
166 /// Words suggested by the spellchecker.
170 explicit MenuItem(Kind kind
) : kind_(kind
), optional_(false) {}
173 QString
const & label
,
174 QString
const & submenu
= QString(),
175 bool optional
= false)
176 : kind_(kind
), label_(label
), submenuname_(submenu
), optional_(optional
)
178 LASSERT(kind
== Submenu
|| kind
== Help
|| kind
== Info
, /**/);
182 QString
const & label
,
183 FuncRequest
const & func
,
184 bool optional
= false,
185 FuncRequest::Origin origin
= FuncRequest::MENU
)
186 : kind_(kind
), label_(label
), func_(func
), optional_(optional
)
188 func_
.origin
= origin
;
191 // boost::shared_ptr<MenuDefinition> needs this apprently...
194 /// The label of a given menuitem
195 QString
label() const { return label_
.split('|')[0]; }
197 /// The keyboard shortcut (usually underlined in the entry)
198 QString
shortcut() const
200 return label_
.contains('|') ? label_
.split('|')[1] : QString();
202 /// The complete label, with label and shortcut separated by a '|'
203 QString
fulllabel() const { return label_
;}
204 /// The kind of entry
205 Kind
kind() const { return kind_
; }
206 /// the action (if relevant)
207 FuncRequest
const & func() const { return func_
; }
208 /// returns true if the entry should be ommited when disabled
209 bool optional() const { return optional_
; }
210 /// returns the status of the lfun associated with this entry
211 FuncStatus
const & status() const { return status_
; }
212 /// returns the status of the lfun associated with this entry
213 FuncStatus
& status() { return status_
; }
214 /// returns the status of the lfun associated with this entry
215 void status(FuncStatus
const & status
) { status_
= status
; }
217 ///returns the binding associated to this action.
218 QString
binding() const
220 if (kind_
!= Command
)
222 // Get the keys bound to this action, but keep only the
224 KeyMap::Bindings bindings
= theTopLevelKeymap().findBindings(func_
);
226 return toqstr(bindings
.begin()->print(KeySequence::ForGui
));
228 LYXERR(Debug::KBMAP
, "No binding for "
229 << lyxaction
.getActionName(func_
.action
)
230 << '(' << func_
.argument() << ')');
234 /// the description of the submenu (if relevant)
235 QString
const & submenuname() const { return submenuname_
; }
236 /// set the description of the submenu
237 void submenuname(QString
const & name
) { submenuname_
= name
; }
239 bool hasSubmenu() const { return !submenu_
.isEmpty(); }
241 MenuDefinition
const & submenu() const { return submenu_
.at(0); }
242 MenuDefinition
& submenu() { return submenu_
[0]; }
244 void setSubmenu(MenuDefinition
const & menu
)
247 submenu_
.append(menu
);
258 QString submenuname_
;
263 /// contains 0 or 1 item.
264 QList
<MenuDefinition
> submenu_
;
268 class MenuDefinition
{
271 typedef std::vector
<MenuItem
> ItemList
;
273 typedef ItemList::const_iterator const_iterator
;
275 explicit MenuDefinition(QString
const & name
= QString()) : name_(name
) {}
280 QString
const & name() const { return name_
; }
282 bool empty() const { return items_
.empty(); }
283 /// Clear the menu content.
284 void clear() { items_
.clear(); }
286 size_t size() const { return items_
.size(); }
288 MenuItem
const & operator[](size_t) const;
290 const_iterator
begin() const { return items_
.begin(); }
292 const_iterator
end() const { return items_
.end(); }
294 // search for func in this menu iteratively, and put menu
296 bool searchMenu(FuncRequest
const & func
, docstring_list
& names
)
299 bool hasFunc(FuncRequest
const &) const;
300 /// Add the menu item unconditionally
301 void add(MenuItem
const & item
) { items_
.push_back(item
); }
302 /// Checks the associated FuncRequest status before adding the
304 void addWithStatusCheck(MenuItem
const &);
305 // Check whether the menu shortcuts are unique
306 void checkShortcuts() const;
308 void expandLastfiles();
309 void expandDocuments();
310 void expandBookmarks();
311 void expandFormats(MenuItem::Kind kind
, Buffer
const * buf
);
312 void expandFloatListInsert(Buffer
const * buf
);
313 void expandFloatInsert(Buffer
const * buf
);
314 void expandFlexInsert(Buffer
const * buf
, InsetLayout::InsetLyXType type
);
315 void expandToc2(Toc
const & toc_list
, size_t from
, size_t to
, int depth
);
316 void expandToc(Buffer
const * buf
);
317 void expandPasteRecent(Buffer
const * buf
);
318 void expandToolbars();
319 void expandBranches(Buffer
const * buf
);
320 void expandIndices(Buffer
const * buf
, bool listof
= false);
321 void expandIndicesContext(Buffer
const * buf
, bool listof
= false);
322 void expandCiteStyles(BufferView
const *);
323 void expandGraphicsGroups(BufferView
const *);
324 void expandSpellingSuggestions(BufferView
const *);
332 /// Helper for std::find_if
336 MenuNamesEqual(QString
const & name
) : name_(name
) {}
337 bool operator()(MenuDefinition
const & menu
) const { return menu
.name() == name_
; }
344 typedef std::vector
<MenuDefinition
> MenuList
;
346 typedef MenuList::const_iterator const_iterator
;
348 typedef MenuList::iterator iterator
;
350 /////////////////////////////////////////////////////////////////////
351 // MenuDefinition implementation
352 /////////////////////////////////////////////////////////////////////
354 void MenuDefinition::addWithStatusCheck(MenuItem
const & i
)
358 case MenuItem::Command
: {
359 FuncStatus status
= lyx::getStatus(i
.func());
360 if (status
.unknown() || (!status
.enabled() && i
.optional()))
363 items_
.back().status(status
);
367 case MenuItem::Submenu
: {
368 bool enabled
= false;
369 if (i
.hasSubmenu()) {
370 for (const_iterator cit
= i
.submenu().begin();
371 cit
!= i
.submenu().end(); ++cit
) {
372 // Only these kind of items affect the status of the submenu
373 if ((cit
->kind() == MenuItem::Command
374 || cit
->kind() == MenuItem::Submenu
375 || cit
->kind() == MenuItem::Help
)
376 && cit
->status().enabled()) {
382 if (enabled
|| !i
.optional()) {
384 items_
.back().status().setEnabled(enabled
);
389 case MenuItem::Separator
:
390 if (!items_
.empty() && items_
.back().kind() != MenuItem::Separator
)
400 void MenuDefinition::read(Lexer
& lex
)
417 md_indiceslistscontext
,
431 md_spellingsuggestions
434 LexerKeyword menutags
[] = {
435 { "bookmarks", md_bookmarks
},
436 { "branches", md_branches
},
437 { "charstyles", md_charstyles
},
438 { "citestyles", md_citestyles
},
439 { "custom", md_custom
},
440 { "documents", md_documents
},
441 { "elements", md_elements
},
442 { "end", md_endmenu
},
443 { "exportformats", md_exportformats
},
444 { "floatinsert", md_floatinsert
},
445 { "floatlistinsert", md_floatlistinsert
},
446 { "graphicsgroups", md_graphicsgroups
},
447 { "importformats", md_importformats
},
448 { "indices", md_indices
},
449 { "indicescontext", md_indicescontext
},
450 { "indiceslists", md_indiceslists
},
451 { "indiceslistscontext", md_indiceslistscontext
},
453 { "lastfiles", md_lastfiles
},
454 { "optitem", md_optitem
},
455 { "optsubmenu", md_optsubmenu
},
456 { "pasterecent", md_pasterecent
},
457 { "separator", md_separator
},
458 { "spellingsuggestions", md_spellingsuggestions
},
459 { "submenu", md_submenu
},
461 { "toolbars", md_toolbars
},
462 { "updateformats", md_updateformats
},
463 { "viewformats", md_viewformats
}
466 lex
.pushTable(menutags
);
467 lex
.setContext("MenuDefinition::read: ");
470 bool optional
= false;
472 while (lex
.isOK() && !quit
) {
476 // fallback to md_item
479 docstring
const name
= translateIfPossible(lex
.getDocString());
481 string
const command
= lex
.getString();
482 FuncRequest func
= lyxaction
.lookupFunc(command
);
483 FuncRequest::Origin origin
= FuncRequest::MENU
;
484 if (name_
.startsWith("context-toc-"))
485 origin
= FuncRequest::TOC
;
486 add(MenuItem(MenuItem::Command
, toqstr(name
), func
, optional
, origin
));
492 add(MenuItem(MenuItem::Separator
));
496 add(MenuItem(MenuItem::Lastfiles
));
500 add(MenuItem(MenuItem::CharStyles
));
504 add(MenuItem(MenuItem::Custom
));
508 add(MenuItem(MenuItem::Elements
));
512 add(MenuItem(MenuItem::Documents
));
516 add(MenuItem(MenuItem::Bookmarks
));
520 add(MenuItem(MenuItem::Toc
));
524 add(MenuItem(MenuItem::ViewFormats
));
527 case md_updateformats
:
528 add(MenuItem(MenuItem::UpdateFormats
));
531 case md_exportformats
:
532 add(MenuItem(MenuItem::ExportFormats
));
535 case md_importformats
:
536 add(MenuItem(MenuItem::ImportFormats
));
539 case md_floatlistinsert
:
540 add(MenuItem(MenuItem::FloatListInsert
));
544 add(MenuItem(MenuItem::FloatInsert
));
548 add(MenuItem(MenuItem::PasteRecent
));
552 add(MenuItem(MenuItem::Toolbars
));
556 add(MenuItem(MenuItem::Branches
));
560 add(MenuItem(MenuItem::CiteStyles
));
563 case md_graphicsgroups
:
564 add(MenuItem(MenuItem::GraphicsGroups
));
567 case md_spellingsuggestions
:
568 add(MenuItem(MenuItem::SpellingSuggestions
));
572 add(MenuItem(MenuItem::Indices
));
575 case md_indicescontext
:
576 add(MenuItem(MenuItem::IndicesContext
));
579 case md_indiceslists
:
580 add(MenuItem(MenuItem::IndicesLists
));
583 case md_indiceslistscontext
:
584 add(MenuItem(MenuItem::IndicesListsContext
));
589 // fallback to md_submenu
592 docstring
const mlabel
= translateIfPossible(lex
.getDocString());
594 docstring
const mname
= lex
.getDocString();
595 add(MenuItem(MenuItem::Submenu
,
596 toqstr(mlabel
), toqstr(mname
), optional
));
606 lex
.printError("Unknown menu tag");
614 MenuItem
const & MenuDefinition::operator[](size_type i
) const
620 bool MenuDefinition::hasFunc(FuncRequest
const & func
) const
622 for (const_iterator it
= begin(), et
= end(); it
!= et
; ++it
)
623 if (it
->func() == func
)
629 void MenuDefinition::checkShortcuts() const
631 // This is a quadratic algorithm, but we do not care because
632 // menus are short enough
633 for (const_iterator it1
= begin(); it1
!= end(); ++it1
) {
634 QString shortcut
= it1
->shortcut();
635 if (shortcut
.isEmpty())
637 if (!it1
->label().contains(shortcut
))
638 LYXERR0("Menu warning: menu entry \""
640 << "\" does not contain shortcut `"
641 << shortcut
<< "'.");
642 for (const_iterator it2
= begin(); it2
!= it1
; ++it2
) {
643 if (!it2
->shortcut().compare(shortcut
, Qt::CaseInsensitive
)) {
644 LYXERR0("Menu warning: menu entries "
645 << '"' << it1
->fulllabel()
646 << "\" and \"" << it2
->fulllabel()
647 << "\" share the same shortcut.");
654 bool MenuDefinition::searchMenu(FuncRequest
const & func
, docstring_list
& names
) const
656 const_iterator m
= begin();
657 const_iterator m_end
= end();
658 for (; m
!= m_end
; ++m
) {
659 if (m
->kind() == MenuItem::Command
&& m
->func() == func
) {
660 names
.push_back(qstring_to_ucs4(m
->label()));
663 if (m
->kind() == MenuItem::Submenu
) {
664 names
.push_back(qstring_to_ucs4(m
->label()));
665 if (!m
->hasSubmenu()) {
666 LYXERR(Debug::GUI
, "Warning: non existing sub menu label="
667 << m
->label() << " name=" << m
->submenuname());
671 if (m
->submenu().searchMenu(func
, names
))
680 bool compareFormat(Format
const * p1
, Format
const * p2
)
686 QString
limitStringLength(docstring
const & str
)
688 size_t const max_item_length
= 45;
690 if (str
.size() > max_item_length
)
691 return toqstr(str
.substr(0, max_item_length
- 3) + "...");
697 void MenuDefinition::expandGraphicsGroups(BufferView
const * bv
)
702 graphics::getGraphicsGroups(bv
->buffer(), grp
);
706 set
<string
>::const_iterator it
= grp
.begin();
707 set
<string
>::const_iterator end
= grp
.end();
708 add(MenuItem(MenuItem::Command
, qt_("No Group"),
709 FuncRequest(LFUN_SET_GRAPHICS_GROUP
)));
710 for (; it
!= end
; it
++) {
711 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(*it
),
712 FuncRequest(LFUN_SET_GRAPHICS_GROUP
, *it
)));
717 void MenuDefinition::expandSpellingSuggestions(BufferView
const * bv
)
722 docstring_list suggestions
;
723 pos_type from
= bv
->cursor().pos();
725 Paragraph
const & par
= bv
->cursor().paragraph();
726 if (!par
.spellCheck(from
, to
, wl
, suggestions
))
728 LYXERR(Debug::GUI
, "Misspelled Word! Suggested Words = ");
730 MenuItem
item(MenuItem::Submenu
, qt_("More Spelling Suggestions"));
731 item
.setSubmenu(MenuDefinition(qt_("More Spelling Suggestions")));
732 for (; i
!= suggestions
.size(); ++i
) {
733 docstring
const & suggestion
= suggestions
[i
];
734 LYXERR(Debug::GUI
, suggestion
);
735 MenuItem
w(MenuItem::Command
, toqstr(suggestion
),
736 FuncRequest(LFUN_WORD_REPLACE
, suggestion
));
740 item
.submenu().add(w
);
747 void MenuDefinition::expandLastfiles()
749 LastFilesSection::LastFiles
const & lf
= theSession().lastFiles().lastFiles();
750 LastFilesSection::LastFiles::const_iterator lfit
= lf
.begin();
754 for (; lfit
!= lf
.end() && ii
<= lyxrc
.num_lastfiles
; ++lfit
, ++ii
) {
755 string
const file
= lfit
->absFilename();
758 label
= QString("%1. %2|%3").arg(ii
)
759 .arg(toqstr(makeDisplayPath(file
, 30))).arg(ii
);
761 label
= QString("%1. %2").arg(ii
)
762 .arg(toqstr(makeDisplayPath(file
, 30)));
763 add(MenuItem(MenuItem::Command
, label
, FuncRequest(LFUN_FILE_OPEN
, file
)));
768 void MenuDefinition::expandDocuments()
770 MenuItem
item(MenuItem::Submenu
, qt_("Invisible"));
771 item
.setSubmenu(MenuDefinition(qt_("Invisible")));
773 Buffer
* first
= theBufferList().first();
779 // We cannot use a for loop as the buffer list cycles.
781 QString label
= toqstr(b
->fileName().displayName(20));
784 bool const shown
= guiApp
->currentView()->workArea(*b
);
785 int ii
= shown
? vis
: invis
;
787 label
= QString::number(ii
) + ". " + label
+ '|' + QString::number(ii
);
789 add(MenuItem(MenuItem::Command
, label
,
790 FuncRequest(LFUN_BUFFER_SWITCH
, b
->absFileName())));
793 item
.submenu().add(MenuItem(MenuItem::Command
, label
,
794 FuncRequest(LFUN_BUFFER_SWITCH
, b
->absFileName())));
797 b
= theBufferList().next(b
);
798 } while (b
!= first
);
799 if (!item
.submenu().empty())
802 add(MenuItem(MenuItem::Info
, qt_("<No Documents Open>")));
806 void MenuDefinition::expandBookmarks()
808 lyx::BookmarksSection
const & bm
= theSession().bookmarks();
811 for (size_t i
= 1; i
<= bm
.size(); ++i
) {
813 string
const file
= bm
.bookmark(i
).filename
.absFilename();
814 QString
const label
= QString("%1. %2|%3").arg(i
)
815 .arg(toqstr(makeDisplayPath(file
, 20))).arg(i
);
816 add(MenuItem(MenuItem::Command
, label
,
817 FuncRequest(LFUN_BOOKMARK_GOTO
, convert
<docstring
>(i
))));
822 add(MenuItem(MenuItem::Info
, qt_("<No Bookmarks Saved Yet>")));
826 void MenuDefinition::expandFormats(MenuItem::Kind kind
, Buffer
const * buf
)
828 if (!buf
&& kind
!= MenuItem::ImportFormats
)
831 typedef vector
<Format
const *> Formats
;
836 case MenuItem::ImportFormats
:
837 formats
= theConverters().importableFormats();
838 action
= LFUN_BUFFER_IMPORT
;
840 case MenuItem::ViewFormats
:
841 formats
= buf
->exportableFormats(true);
842 action
= LFUN_BUFFER_VIEW
;
844 case MenuItem::UpdateFormats
:
845 formats
= buf
->exportableFormats(true);
846 action
= LFUN_BUFFER_UPDATE
;
849 formats
= buf
->exportableFormats(false);
850 action
= LFUN_BUFFER_EXPORT
;
852 sort(formats
.begin(), formats
.end(), &compareFormat
);
854 bool const view_update
= (kind
== MenuItem::ViewFormats
855 || kind
== MenuItem::UpdateFormats
);
859 smenue
= (kind
== MenuItem::ViewFormats
?
860 qt_("View [Other Formats]|F")
861 : qt_("Update [Other Formats]|p"));
862 MenuItem
item(MenuItem::Submenu
, smenue
);
863 item
.setSubmenu(MenuDefinition(smenue
));
865 Formats::const_iterator fit
= formats
.begin();
866 Formats::const_iterator end
= formats
.end();
867 for (; fit
!= end
; ++fit
) {
871 docstring lab
= from_utf8((*fit
)->prettyname());
872 docstring scut
= from_utf8((*fit
)->shortcut());
873 docstring
const tmplab
= lab
;
876 lab
+= char_type('|') + scut
;
877 docstring lab_i18n
= translateIfPossible(lab
);
878 bool const untranslated
= (lab
== lab_i18n
);
879 QString
const shortcut
= toqstr(split(lab_i18n
, lab
, '|'));
880 QString label
= toqstr(lab
);
882 // this might happen if the shortcut
883 // has been redefined
884 label
= toqstr(translateIfPossible(tmplab
));
887 case MenuItem::ImportFormats
:
890 case MenuItem::ViewFormats
:
891 case MenuItem::UpdateFormats
:
892 if ((*fit
)->name() == buf
->getDefaultOutputFormat()) {
893 docstring lbl
= (kind
== MenuItem::ViewFormats
?
894 bformat(_("View [%1$s]"), qstring_to_ucs4(label
))
895 : bformat(_("Update [%1$s]"), qstring_to_ucs4(label
)));
896 MenuItem
w(MenuItem::Command
, toqstr(lbl
),
897 FuncRequest(action
, (*fit
)->name()));
901 case MenuItem::ExportFormats
:
902 if (!(*fit
)->documentFormat())
906 LASSERT(false, /**/);
909 if (!shortcut
.isEmpty())
910 label
+= '|' + shortcut
;
914 item
.submenu().addWithStatusCheck(MenuItem(MenuItem::Command
, label
,
915 FuncRequest(action
, (*fit
)->name())));
917 item
.submenu().add(MenuItem(MenuItem::Command
, label
,
918 FuncRequest(action
, (*fit
)->name())));
921 addWithStatusCheck(MenuItem(MenuItem::Command
, label
,
922 FuncRequest(action
, (*fit
)->name())));
924 add(MenuItem(MenuItem::Command
, label
,
925 FuncRequest(action
, (*fit
)->name())));
933 void MenuDefinition::expandFloatListInsert(Buffer
const * buf
)
938 FloatList
const & floats
= buf
->params().documentClass().floats();
939 FloatList::const_iterator cit
= floats
.begin();
940 FloatList::const_iterator end
= floats
.end();
941 for (; cit
!= end
; ++cit
) {
942 addWithStatusCheck(MenuItem(MenuItem::Command
,
943 qt_(cit
->second
.listName()),
944 FuncRequest(LFUN_FLOAT_LIST_INSERT
,
945 cit
->second
.type())));
950 void MenuDefinition::expandFloatInsert(Buffer
const * buf
)
955 FloatList
const & floats
= buf
->params().documentClass().floats();
956 FloatList::const_iterator cit
= floats
.begin();
957 FloatList::const_iterator end
= floats
.end();
958 for (; cit
!= end
; ++cit
) {
960 QString
const label
= qt_(cit
->second
.name());
961 addWithStatusCheck(MenuItem(MenuItem::Command
, label
,
962 FuncRequest(LFUN_FLOAT_INSERT
,
963 cit
->second
.type())));
968 void MenuDefinition::expandFlexInsert(
969 Buffer
const * buf
, InsetLayout::InsetLyXType type
)
974 TextClass::InsetLayouts
const & insetLayouts
=
975 buf
->params().documentClass().insetLayouts();
976 TextClass::InsetLayouts::const_iterator cit
= insetLayouts
.begin();
977 TextClass::InsetLayouts::const_iterator end
= insetLayouts
.end();
978 for (; cit
!= end
; ++cit
) {
979 if (cit
->second
.lyxtype() == type
) {
980 docstring
const label
= cit
->first
;
981 addWithStatusCheck(MenuItem(MenuItem::Command
,
982 toqstr(translateIfPossible(label
)),
983 FuncRequest(LFUN_FLEX_INSERT
, Lexer::quoteString(label
))));
986 // FIXME This is a little clunky.
987 if (items_
.empty() && type
== InsetLayout::CUSTOM
)
988 add(MenuItem(MenuItem::Help
, qt_("No Custom Insets Defined!")));
992 size_t const max_number_of_items
= 25;
994 void MenuDefinition::expandToc2(Toc
const & toc_list
,
995 size_t from
, size_t to
, int depth
)
997 int shortcut_count
= 0;
999 // check whether depth is smaller than the smallest depth in toc.
1000 int min_depth
= 1000;
1001 for (size_t i
= from
; i
< to
; ++i
)
1002 min_depth
= min(min_depth
, toc_list
[i
].depth());
1003 if (min_depth
> depth
)
1006 if (to
- from
<= max_number_of_items
) {
1007 for (size_t i
= from
; i
< to
; ++i
) {
1008 QString
label(4 * max(0, toc_list
[i
].depth() - depth
), ' ');
1009 label
+= limitStringLength(toc_list
[i
].str());
1010 if (toc_list
[i
].depth() == depth
1011 && shortcut_count
< 9) {
1012 if (label
.contains(QString::number(shortcut_count
+ 1)))
1013 label
+= '|' + QString::number(++shortcut_count
);
1015 add(MenuItem(MenuItem::Command
, label
,
1016 FuncRequest(toc_list
[i
].action())));
1021 size_t new_pos
= pos
+ 1;
1022 while (new_pos
< to
&& toc_list
[new_pos
].depth() > depth
)
1025 QString
label(4 * max(0, toc_list
[pos
].depth() - depth
), ' ');
1026 label
+= limitStringLength(toc_list
[pos
].str());
1027 if (toc_list
[pos
].depth() == depth
&&
1028 shortcut_count
< 9) {
1029 if (label
.contains(QString::number(shortcut_count
+ 1)))
1030 label
+= '|' + QString::number(++shortcut_count
);
1032 if (new_pos
== pos
+ 1) {
1033 add(MenuItem(MenuItem::Command
,
1034 label
, FuncRequest(toc_list
[pos
].action())));
1037 sub
.expandToc2(toc_list
, pos
, new_pos
, depth
+ 1);
1038 MenuItem
item(MenuItem::Submenu
, label
);
1039 item
.setSubmenu(sub
);
1048 void MenuDefinition::expandToc(Buffer
const * buf
)
1050 // To make things very cleanly, we would have to pass buf to
1051 // all MenuItem constructors and to expandToc2. However, we
1052 // know that all the entries in a TOC will be have status_ ==
1053 // OK, so we avoid this unnecessary overhead (JMarc)
1056 add(MenuItem(MenuItem::Info
, qt_("<No Document Open>")));
1060 // Add an entry for the master doc if this is a child doc
1061 Buffer
const * const master
= buf
->masterBuffer();
1062 if (buf
!= master
) {
1063 ParIterator
const pit
= par_iterator_begin(master
->inset());
1064 string
const arg
= convert
<string
>(pit
->id());
1065 FuncRequest
f(LFUN_PARAGRAPH_GOTO
, arg
);
1066 add(MenuItem(MenuItem::Command
, qt_("Master Document"), f
));
1069 MenuDefinition other_lists
;
1071 FloatList
const & floatlist
= buf
->params().documentClass().floats();
1072 TocList
const & toc_list
= buf
->tocBackend().tocs();
1073 TocList::const_iterator cit
= toc_list
.begin();
1074 TocList::const_iterator end
= toc_list
.end();
1075 for (; cit
!= end
; ++cit
) {
1076 // Handle this later
1077 if (cit
->first
== "tableofcontents")
1080 MenuDefinition submenu
;
1081 if (cit
->second
.size() >= 30) {
1082 FuncRequest
f(LFUN_DIALOG_SHOW
, "toc " + cit
->first
);
1083 submenu
.add(MenuItem(MenuItem::Command
, qt_("Open Navigator..."), f
));
1085 TocIterator ccit
= cit
->second
.begin();
1086 TocIterator eend
= cit
->second
.end();
1087 for (; ccit
!= eend
; ++ccit
) {
1088 submenu
.add(MenuItem(MenuItem::Command
,
1089 limitStringLength(ccit
->str()),
1090 FuncRequest(ccit
->action())));
1094 MenuItem
item(MenuItem::Submenu
, guiName(cit
->first
, buf
->params()));
1095 item
.setSubmenu(submenu
);
1096 if (floatlist
.typeExist(cit
->first
) || cit
->first
== "child") {
1097 // Those two types deserve to be in the main menu.
1098 item
.setSubmenu(submenu
);
1101 other_lists
.add(item
);
1103 if (!other_lists
.empty()) {
1104 MenuItem
item(MenuItem::Submenu
, qt_("Other Lists"));
1105 item
.setSubmenu(other_lists
);
1109 // Handle normal TOC
1110 cit
= toc_list
.find("tableofcontents");
1112 LYXERR(Debug::GUI
, "No table of contents.");
1114 if (cit
->second
.size() > 0 )
1115 expandToc2(cit
->second
, 0, cit
->second
.size(), 0);
1117 add(MenuItem(MenuItem::Info
, qt_("<Empty Table of Contents>")));
1122 void MenuDefinition::expandPasteRecent(Buffer
const * buf
)
1124 docstring_list
const sel
= cap::availableSelections(buf
);
1126 docstring_list::const_iterator cit
= sel
.begin();
1127 docstring_list::const_iterator end
= sel
.end();
1129 for (unsigned int index
= 0; cit
!= end
; ++cit
, ++index
) {
1130 add(MenuItem(MenuItem::Command
, toqstr(*cit
),
1131 FuncRequest(LFUN_PASTE
, convert
<string
>(index
))));
1136 void MenuDefinition::expandToolbars()
1138 MenuDefinition other_lists
;
1139 // extracts the toolbars from the backend
1140 Toolbars::Infos::const_iterator cit
= guiApp
->toolbars().begin();
1141 Toolbars::Infos::const_iterator end
= guiApp
->toolbars().end();
1142 for (; cit
!= end
; ++cit
) {
1143 MenuItem
const item(MenuItem::Command
, toqstr(cit
->gui_name
),
1144 FuncRequest(LFUN_TOOLBAR_TOGGLE
, cit
->name
));
1145 if (guiApp
->toolbars().isMainToolbar(cit
->name
))
1148 other_lists
.add(item
);
1151 if (!other_lists
.empty()) {
1152 MenuItem
item(MenuItem::Submenu
, qt_("Other Toolbars"));
1153 item
.setSubmenu(other_lists
);
1159 void MenuDefinition::expandBranches(Buffer
const * buf
)
1164 BufferParams
const & master_params
= buf
->masterBuffer()->params();
1165 BufferParams
const & params
= buf
->params();
1166 if (params
.branchlist().empty() && master_params
.branchlist().empty() ) {
1167 add(MenuItem(MenuItem::Help
, qt_("No Branches Set for Document!")));
1171 BranchList::const_iterator cit
= master_params
.branchlist().begin();
1172 BranchList::const_iterator end
= master_params
.branchlist().end();
1174 for (int ii
= 1; cit
!= end
; ++cit
, ++ii
) {
1175 docstring label
= cit
->branch();
1177 label
= convert
<docstring
>(ii
) + ". " + label
1178 + char_type('|') + convert
<docstring
>(ii
);
1180 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(label
),
1181 FuncRequest(LFUN_BRANCH_INSERT
,
1185 if (buf
== buf
->masterBuffer())
1188 MenuDefinition child_branches
;
1190 BranchList::const_iterator ccit
= params
.branchlist().begin();
1191 BranchList::const_iterator cend
= params
.branchlist().end();
1193 for (int ii
= 1; ccit
!= cend
; ++ccit
, ++ii
) {
1194 docstring label
= ccit
->branch();
1196 label
= convert
<docstring
>(ii
) + ". " + label
1197 + char_type('|') + convert
<docstring
>(ii
);
1199 child_branches
.addWithStatusCheck(MenuItem(MenuItem::Command
,
1201 FuncRequest(LFUN_BRANCH_INSERT
,
1205 if (!child_branches
.empty()) {
1206 MenuItem
item(MenuItem::Submenu
, qt_("Child Document"));
1207 item
.setSubmenu(child_branches
);
1213 void MenuDefinition::expandIndices(Buffer
const * buf
, bool listof
)
1218 BufferParams
const & params
= buf
->masterBuffer()->params();
1219 if (!params
.use_indices
) {
1221 addWithStatusCheck(MenuItem(MenuItem::Command
,
1222 qt_("Index List|I"),
1223 FuncRequest(LFUN_INDEX_PRINT
,
1224 from_ascii("idx"))));
1226 addWithStatusCheck(MenuItem(MenuItem::Command
,
1227 qt_("Index Entry|d"),
1228 FuncRequest(LFUN_INDEX_INSERT
,
1229 from_ascii("idx"))));
1233 if (params
.indiceslist().empty())
1236 IndicesList::const_iterator cit
= params
.indiceslist().begin();
1237 IndicesList::const_iterator end
= params
.indiceslist().end();
1239 for (int ii
= 1; cit
!= end
; ++cit
, ++ii
) {
1241 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(cit
->index()),
1242 FuncRequest(LFUN_INDEX_PRINT
,
1245 docstring label
= _("Index Entry");
1246 label
+= " (" + cit
->index() + ")";
1247 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(label
),
1248 FuncRequest(LFUN_INDEX_INSERT
,
1255 void MenuDefinition::expandIndicesContext(Buffer
const * buf
, bool listof
)
1260 BufferParams
const & params
= buf
->masterBuffer()->params();
1261 if (!params
.use_indices
|| params
.indiceslist().empty())
1264 IndicesList::const_iterator cit
= params
.indiceslist().begin();
1265 IndicesList::const_iterator end
= params
.indiceslist().end();
1267 for (int ii
= 1; cit
!= end
; ++cit
, ++ii
) {
1269 InsetCommandParams
p(INDEX_PRINT_CODE
);
1270 p
["type"] = cit
->shortcut();
1271 string
const data
= InsetCommand::params2string("index_print", p
);
1272 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(cit
->index()),
1273 FuncRequest(LFUN_NEXT_INSET_MODIFY
, data
)));
1275 docstring label
= _("Index Entry");
1276 label
+= " (" + cit
->index() + ")";
1277 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(label
),
1278 FuncRequest(LFUN_NEXT_INSET_MODIFY
,
1279 from_ascii("changetype ") + cit
->shortcut())));
1285 void MenuDefinition::expandCiteStyles(BufferView
const * bv
)
1290 Inset
const * inset
= bv
->cursor().nextInset();
1291 if (!inset
|| inset
->lyxCode() != CITE_CODE
) {
1292 add(MenuItem(MenuItem::Command
,
1293 qt_("No Citation in Scope!"),
1294 FuncRequest(LFUN_NOACTION
)));
1297 InsetCommand
const * citinset
=
1298 static_cast<InsetCommand
const *>(inset
);
1300 Buffer
const * buf
= &bv
->buffer();
1301 docstring key
= citinset
->getParam("key");
1302 // we can only handle one key currently
1303 if (contains(key
, ','))
1304 key
= qstring_to_ucs4(toqstr(key
).split(',')[0]);
1306 vector
<CiteStyle
> citeStyleList
= citeStyles(buf
->params().citeEngine());
1307 docstring_list citeStrings
=
1308 buf
->masterBibInfo().getCiteStrings(key
, bv
->buffer());
1310 docstring_list::const_iterator cit
= citeStrings
.begin();
1311 docstring_list::const_iterator end
= citeStrings
.end();
1313 for (int ii
= 1; cit
!= end
; ++cit
, ++ii
) {
1314 docstring label
= *cit
;
1316 CiteStyle cst
= citeStyleList
[ii
- 1];
1318 addWithStatusCheck(MenuItem(MenuItem::Command
, toqstr(label
),
1319 FuncRequest(LFUN_NEXT_INSET_MODIFY
,
1320 "changetype " + from_utf8(citationStyleToString(cs
)))));
1327 /////////////////////////////////////////////////////////////////////
1328 // Menu::Impl definition and implementation
1329 /////////////////////////////////////////////////////////////////////
1333 /// populates the menu or one of its submenu
1334 /// This is used as a recursive function
1335 void populate(QMenu
& qMenu
, MenuDefinition
const & menu
);
1337 /// Only needed for top level menus.
1338 MenuDefinition
* top_level_menu
;
1341 /// the name of this menu
1347 /// Get a MenuDefinition item label from the menu backend
1348 static QString
label(MenuItem
const & mi
)
1350 QString label
= mi
.label();
1351 label
.replace("&", "&&");
1353 QString shortcut
= mi
.shortcut();
1354 if (!shortcut
.isEmpty()) {
1355 int pos
= label
.indexOf(shortcut
);
1357 //label.insert(pos, 1, char_type('&'));
1358 label
.replace(pos
, 0, "&");
1361 QString
const binding
= mi
.binding();
1362 if (!binding
.isEmpty())
1363 label
+= '\t' + binding
;
1368 void Menu::Impl::populate(QMenu
& qMenu
, MenuDefinition
const & menu
)
1370 LYXERR(Debug::GUI
, "populating menu " << menu
.name());
1371 if (menu
.size() == 0) {
1372 LYXERR(Debug::GUI
, "\tERROR: empty menu " << menu
.name());
1375 LYXERR(Debug::GUI
, " ***** menu entries " << menu
.size());
1376 MenuDefinition::const_iterator m
= menu
.begin();
1377 MenuDefinition::const_iterator end
= menu
.end();
1378 for (; m
!= end
; ++m
) {
1379 if (m
->kind() == MenuItem::Separator
)
1380 qMenu
.addSeparator();
1381 else if (m
->kind() == MenuItem::Submenu
) {
1382 QMenu
* subMenu
= qMenu
.addMenu(label(*m
));
1383 populate(*subMenu
, m
->submenu());
1384 subMenu
->setEnabled(m
->status().enabled());
1386 // we have a MenuItem::Command
1387 qMenu
.addAction(new Action(view
, QIcon(), label(*m
),
1388 m
->func(), QString(), &qMenu
));
1393 /////////////////////////////////////////////////////////////////////
1394 // Menu implementation
1395 /////////////////////////////////////////////////////////////////////
1397 Menu::Menu(GuiView
* gv
, QString
const & name
, bool top_level
)
1398 : QMenu(gv
), d(new Menu::Impl
)
1400 d
->top_level_menu
= top_level
? new MenuDefinition
: 0;
1404 if (d
->top_level_menu
)
1405 connect(this, SIGNAL(aboutToShow()), this, SLOT(updateView()));
1411 delete d
->top_level_menu
;
1416 void Menu::updateView()
1418 guiApp
->menus().updateMenu(this);
1422 /////////////////////////////////////////////////////////////////////
1423 // Menus::Impl definition and implementation
1424 /////////////////////////////////////////////////////////////////////
1426 struct Menus::Impl
{
1428 bool hasMenu(QString
const &) const;
1430 MenuDefinition
& getMenu(QString
const &);
1432 MenuDefinition
const & getMenu(QString
const &) const;
1434 /// Expands some special entries of the menu
1435 /** The entries with the following kind are expanded to a
1436 sequence of Command MenuItems: Lastfiles, Documents,
1437 ViewFormats, ExportFormats, UpdateFormats, Branches, Indices
1439 void expand(MenuDefinition
const & frommenu
, MenuDefinition
& tomenu
,
1440 BufferView
const *) const;
1442 /// Initialize specific MACOS X menubar
1443 void macxMenuBarInit(GuiView
* view
, QMenuBar
* qmb
);
1445 /// Mac special menu.
1446 /** This defines a menu whose entries list the FuncRequests
1447 that will be removed by expand() in other menus. This is
1448 used by the Qt/Mac code.
1450 NOTE: Qt does not remove the menu items when clearing a QMenuBar,
1451 such that the items will keep accessing the FuncRequests in
1452 the MenuDefinition. While Menus::Impl might be recreated,
1453 we keep mac_special_menu_ in memory by making it static.
1455 static MenuDefinition mac_special_menu_
;
1460 MenuDefinition menubar_
;
1462 typedef QMap
<GuiView
*, QHash
<QString
, Menu
*> > NameMap
;
1464 /// name to menu for \c menu() method.
1469 MenuDefinition
Menus::Impl::mac_special_menu_
;
1473 Here is what the Qt documentation says about how a menubar is chosen:
1475 1) If the window has a QMenuBar then it is used. 2) If the window
1476 is a modal then its menubar is used. If no menubar is specified
1477 then a default menubar is used (as documented below) 3) If the
1478 window has no parent then the default menubar is used (as
1481 The above 3 steps are applied all the way up the parent window
1482 chain until one of the above are satisifed. If all else fails a
1483 default menubar will be created, the default menubar on Qt/Mac is
1484 an empty menubar, however you can create a different default
1485 menubar by creating a parentless QMenuBar, the first one created
1486 will thus be designated the default menubar, and will be used
1487 whenever a default menubar is needed.
1489 Thus, for Qt/Mac, we add the menus to a free standing menubar, so
1490 that this menubar will be used also when one of LyX' dialogs has
1493 void Menus::Impl::macxMenuBarInit(GuiView
* view
, QMenuBar
* qmb
)
1495 /* Since Qt 4.2, the qt/mac menu code has special code for
1496 specifying the role of a menu entry. However, it does not
1497 work very well with our scheme of creating menus on demand,
1498 and therefore we need to put these entries in a special
1499 invisible menu. (JMarc)
1502 /* The entries of our special mac menu. If we add support for
1503 * special entries in Menus, we could imagine something
1505 * SpecialItem About " "About LyX" "dialog-show aboutlyx"
1506 * and therefore avoid hardcoding. I am not sure it is worth
1507 * the hassle, though. (JMarc)
1509 struct MacMenuEntry
{
1513 QAction::MenuRole role
;
1516 MacMenuEntry entries
[] = {
1517 {LFUN_DIALOG_SHOW
, "aboutlyx", "About LyX",
1518 QAction::AboutRole
},
1519 {LFUN_DIALOG_SHOW
, "prefs", "Preferences",
1520 QAction::PreferencesRole
},
1521 {LFUN_RECONFIGURE
, "", "Reconfigure",
1522 QAction::ApplicationSpecificRole
},
1523 {LFUN_LYX_QUIT
, "", "Quit LyX", QAction::QuitRole
}
1525 const size_t num_entries
= sizeof(entries
) / sizeof(entries
[0]);
1527 // the special menu for Menus. Fill it up only once.
1528 if (mac_special_menu_
.size() == 0) {
1529 for (size_t i
= 0 ; i
< num_entries
; ++i
) {
1530 FuncRequest
const func(entries
[i
].action
,
1531 from_utf8(entries
[i
].arg
));
1532 mac_special_menu_
.add(MenuItem(MenuItem::Command
,
1533 entries
[i
].label
, func
));
1537 // add the entries to a QMenu that will eventually be empty
1538 // and therefore invisible.
1539 QMenu
* qMenu
= qmb
->addMenu("special");
1540 MenuDefinition::const_iterator cit
= mac_special_menu_
.begin();
1541 MenuDefinition::const_iterator end
= mac_special_menu_
.end();
1542 for (size_t i
= 0 ; cit
!= end
; ++cit
, ++i
) {
1543 Action
* action
= new Action(view
, QIcon(), cit
->label(),
1544 cit
->func(), QString(), qMenu
);
1545 action
->setMenuRole(entries
[i
].role
);
1546 qMenu
->addAction(action
);
1551 void Menus::Impl::expand(MenuDefinition
const & frommenu
,
1552 MenuDefinition
& tomenu
, BufferView
const * bv
) const
1554 if (!tomenu
.empty())
1557 for (MenuDefinition::const_iterator cit
= frommenu
.begin();
1558 cit
!= frommenu
.end() ; ++cit
) {
1559 Buffer
const * buf
= bv
? &bv
->buffer() : 0;
1560 switch (cit
->kind()) {
1561 case MenuItem::Lastfiles
:
1562 tomenu
.expandLastfiles();
1565 case MenuItem::Documents
:
1566 tomenu
.expandDocuments();
1569 case MenuItem::Bookmarks
:
1570 tomenu
.expandBookmarks();
1573 case MenuItem::ImportFormats
:
1574 case MenuItem::ViewFormats
:
1575 case MenuItem::UpdateFormats
:
1576 case MenuItem::ExportFormats
:
1577 tomenu
.expandFormats(cit
->kind(), buf
);
1580 case MenuItem::CharStyles
:
1581 tomenu
.expandFlexInsert(buf
, InsetLayout::CHARSTYLE
);
1584 case MenuItem::Custom
:
1585 tomenu
.expandFlexInsert(buf
, InsetLayout::CUSTOM
);
1588 case MenuItem::Elements
:
1589 tomenu
.expandFlexInsert(buf
, InsetLayout::ELEMENT
);
1592 case MenuItem::FloatListInsert
:
1593 tomenu
.expandFloatListInsert(buf
);
1596 case MenuItem::FloatInsert
:
1597 tomenu
.expandFloatInsert(buf
);
1600 case MenuItem::PasteRecent
:
1601 tomenu
.expandPasteRecent(buf
);
1604 case MenuItem::Toolbars
:
1605 tomenu
.expandToolbars();
1608 case MenuItem::Branches
:
1609 tomenu
.expandBranches(buf
);
1612 case MenuItem::Indices
:
1613 tomenu
.expandIndices(buf
);
1616 case MenuItem::IndicesContext
:
1617 tomenu
.expandIndicesContext(buf
);
1620 case MenuItem::IndicesLists
:
1621 tomenu
.expandIndices(buf
, true);
1624 case MenuItem::IndicesListsContext
:
1625 tomenu
.expandIndicesContext(buf
, true);
1628 case MenuItem::CiteStyles
:
1629 tomenu
.expandCiteStyles(bv
);
1633 tomenu
.expandToc(buf
);
1636 case MenuItem::GraphicsGroups
:
1637 tomenu
.expandGraphicsGroups(bv
);
1640 case MenuItem::SpellingSuggestions
:
1641 tomenu
.expandSpellingSuggestions(bv
);
1644 case MenuItem::Submenu
: {
1645 MenuItem
item(*cit
);
1646 item
.setSubmenu(MenuDefinition(cit
->submenuname()));
1647 expand(getMenu(cit
->submenuname()), item
.submenu(), bv
);
1648 tomenu
.addWithStatusCheck(item
);
1652 case MenuItem::Info
:
1653 case MenuItem::Help
:
1654 case MenuItem::Separator
:
1655 tomenu
.addWithStatusCheck(*cit
);
1658 case MenuItem::Command
:
1659 if (!mac_special_menu_
.hasFunc(cit
->func()))
1660 tomenu
.addWithStatusCheck(*cit
);
1664 // we do not want the menu to end with a separator
1665 if (!tomenu
.empty() && tomenu
.items_
.back().kind() == MenuItem::Separator
)
1666 tomenu
.items_
.pop_back();
1668 // Check whether the shortcuts are unique
1669 tomenu
.checkShortcuts();
1673 bool Menus::Impl::hasMenu(QString
const & name
) const
1675 return find_if(menulist_
.begin(), menulist_
.end(),
1676 MenuNamesEqual(name
)) != menulist_
.end();
1680 MenuDefinition
const & Menus::Impl::getMenu(QString
const & name
) const
1682 const_iterator cit
= find_if(menulist_
.begin(), menulist_
.end(),
1683 MenuNamesEqual(name
));
1684 if (cit
== menulist_
.end())
1685 LYXERR0("No submenu named " << name
);
1686 LASSERT(cit
!= menulist_
.end(), /**/);
1691 MenuDefinition
& Menus::Impl::getMenu(QString
const & name
)
1693 iterator it
= find_if(menulist_
.begin(), menulist_
.end(),
1694 MenuNamesEqual(name
));
1695 if (it
== menulist_
.end())
1696 LYXERR0("No submenu named " << name
);
1697 LASSERT(it
!= menulist_
.end(), /**/);
1702 /////////////////////////////////////////////////////////////////////
1706 /////////////////////////////////////////////////////////////////////
1708 Menus::Menus() : d(new Impl
) {}
1724 void Menus::read(Lexer
& lex
)
1732 LexerKeyword menutags
[] = {
1733 { "end", md_endmenuset
},
1734 { "menu", md_menu
},
1735 { "menubar", md_menubar
}
1738 // consistency check
1739 if (compare_ascii_no_case(lex
.getString(), "menuset"))
1740 LYXERR0("Menus::read: ERROR wrong token: `" << lex
.getString() << '\'');
1742 lex
.pushTable(menutags
);
1743 lex
.setContext("Menus::read");
1747 while (lex
.isOK() && !quit
) {
1748 switch (lex
.lex()) {
1750 d
->menubar_
.read(lex
);
1754 QString
const name
= toqstr(lex
.getDocString());
1755 if (d
->hasMenu(name
))
1756 d
->getMenu(name
).read(lex
);
1758 MenuDefinition
menu(name
);
1760 d
->menulist_
.push_back(menu
);
1768 lex
.printError("Unknown menu tag");
1776 bool Menus::searchMenu(FuncRequest
const & func
,
1777 docstring_list
& names
) const
1779 MenuDefinition menu
;
1780 d
->expand(d
->menubar_
, menu
, 0);
1781 return menu
.searchMenu(func
, names
);
1785 void Menus::fillMenuBar(QMenuBar
* qmb
, GuiView
* view
, bool initial
)
1789 // setup special mac specific menu items, but only do this
1790 // the first time a QMenuBar is created. Otherwise Qt will
1791 // create duplicate items in the application menu. It seems
1792 // that Qt does not remove them when the QMenubar is cleared.
1793 LYXERR(Debug::GUI
, "Creating Mac OS X special menu bar");
1794 d
->macxMenuBarInit(view
, qmb
);
1797 // Clear all menubar contents before filling it.
1801 LYXERR(Debug::GUI
, "populating menu bar" << d
->menubar_
.name());
1803 if (d
->menubar_
.size() == 0) {
1804 LYXERR(Debug::GUI
, "\tERROR: empty menu bar"
1805 << d
->menubar_
.name());
1808 LYXERR(Debug::GUI
, "menu bar entries " << d
->menubar_
.size());
1810 MenuDefinition menu
;
1811 BufferView
* bv
= 0;
1813 bv
= view
->currentBufferView();
1814 d
->expand(d
->menubar_
, menu
, bv
);
1816 MenuDefinition::const_iterator m
= menu
.begin();
1817 MenuDefinition::const_iterator end
= menu
.end();
1819 for (; m
!= end
; ++m
) {
1821 if (m
->kind() != MenuItem::Submenu
) {
1822 LYXERR(Debug::GUI
, "\tERROR: not a submenu " << m
->label());
1826 LYXERR(Debug::GUI
, "menu bar item " << m
->label()
1827 << " is a submenu named " << m
->submenuname());
1829 QString name
= m
->submenuname();
1830 if (!d
->hasMenu(name
)) {
1831 LYXERR(Debug::GUI
, "\tERROR: " << name
1832 << " submenu has no menu!");
1836 Menu
* menu
= new Menu(view
, m
->submenuname(), true);
1837 menu
->setTitle(label(*m
));
1840 d
->name_map_
[view
][name
] = menu
;
1845 void Menus::updateMenu(Menu
* qmenu
)
1847 LYXERR(Debug::GUI
, "Triggered menu: " << qmenu
->d
->name
);
1850 if (qmenu
->d
->name
.isEmpty())
1853 // Here, We make sure that theLyXFunc points to the correct LyXView.
1854 theLyXFunc().setLyXView(qmenu
->d
->view
);
1856 if (!d
->hasMenu(qmenu
->d
->name
)) {
1857 qmenu
->addAction(qt_("No Action Defined!"));
1858 LYXERR(Debug::GUI
, "\tWARNING: non existing menu: "
1863 MenuDefinition
const & fromLyxMenu
= d
->getMenu(qmenu
->d
->name
);
1864 BufferView
* bv
= 0;
1866 bv
= qmenu
->d
->view
->currentBufferView();
1867 d
->expand(fromLyxMenu
, *qmenu
->d
->top_level_menu
, bv
);
1868 qmenu
->d
->populate(*qmenu
, *qmenu
->d
->top_level_menu
);
1872 Menu
* Menus::menu(QString
const & name
, GuiView
& view
)
1874 LYXERR(Debug::GUI
, "Context menu requested: " << name
);
1875 Menu
* menu
= d
->name_map_
[&view
].value(name
, 0);
1876 if (!menu
&& !name
.startsWith("context-")) {
1877 LYXERR0("requested context menu not found: " << name
);
1881 menu
= new Menu(&view
, name
, true);
1882 d
->name_map_
[&view
][name
] = menu
;
1886 } // namespace frontend
1889 #include "moc_Menus.cpp"