X-Git-Url: https://git.lyx.org/gitweb/?a=blobdiff_plain;f=src%2Ffrontends%2Fqt4%2FMenus.cpp;h=627ec4c4c95c31be9ff7c4694c7a3266488c1fab;hb=28be7d552f62cc02fa86d7f79201d089bfb2d7b5;hp=0985a9d2c571830cd72d81595e603b88a0bbf6a2;hpb=c61ef8b205ee0fb6473af0f120c359e7d1ebe83c;p=lyx.git diff --git a/src/frontends/qt4/Menus.cpp b/src/frontends/qt4/Menus.cpp index 0985a9d2c5..627ec4c4c9 100644 --- a/src/frontends/qt4/Menus.cpp +++ b/src/frontends/qt4/Menus.cpp @@ -47,10 +47,12 @@ #include "LyXRC.h" #include "lyxfind.h" #include "Paragraph.h" +#include "ParagraphParameters.h" #include "ParIterator.h" #include "Session.h" #include "SpellChecker.h" #include "TextClass.h" +#include "Text.h" #include "TocBackend.h" #include "Toolbars.h" #include "WordLangTuple.h" @@ -58,6 +60,7 @@ #include "insets/Inset.h" #include "insets/InsetCitation.h" #include "insets/InsetGraphics.h" +#include "insets/InsetQuotes.h" #include "support/lassert.h" #include "support/convert.h" @@ -76,9 +79,8 @@ #include #endif -#include "support/shared_ptr.h" - #include +#include #include using namespace std; @@ -133,6 +135,9 @@ public: /** This is a list of exportable formats typically for the File->Export menu. */ ExportFormats, + /** This exports the document default format + typically for the File->Export menu. */ + ExportFormat, /** This is a list of importable formats typically for the File->Import menu. */ ImportFormats, @@ -185,7 +190,11 @@ public: Captions, /** This is the list of captions available in the InsetCaption context menu. */ - SwitchCaptions + SwitchCaptions, + /** Commands to separate environments. */ + EnvironmentSeparators, + /** This is the list of quotation marks available */ + SwitchQuotes }; explicit MenuItem(Kind kind) : kind_(kind), optional_(false) {} @@ -195,10 +204,10 @@ public: QString const & submenu = QString(), QString const & tooltip = QString(), bool optional = false) - : kind_(kind), label_(label), submenuname_(submenu), - tooltip_(tooltip), optional_(optional) + : kind_(kind), label_(label), func_(make_shared()), + submenuname_(submenu), tooltip_(tooltip), optional_(optional) { - LASSERT(kind == Submenu || kind == Help || kind == Info, /**/); + LATTEST(kind == Submenu || kind == Help || kind == Info); } MenuItem(Kind kind, @@ -207,15 +216,12 @@ public: QString const & tooltip = QString(), bool optional = false, FuncRequest::Origin origin = FuncRequest::MENU) - : kind_(kind), label_(label), func_(func), + : kind_(kind), label_(label), func_(make_shared(func)), tooltip_(tooltip), optional_(optional) { - func_.setOrigin(origin); + func_->setOrigin(origin); } - // shared_ptr needs this apprently... - ~MenuItem() {} - /// The label of a given menuitem QString label() const { @@ -234,7 +240,7 @@ public: /// The kind of entry Kind kind() const { return kind_; } /// the action (if relevant) - FuncRequest const & func() const { return func_; } + shared_ptr func() const { return func_; } /// the tooltip QString const & tooltip() const { return tooltip_; } /// returns true if the entry should be omitted when disabled @@ -253,13 +259,13 @@ public: return QString(); // Get the keys bound to this action, but keep only the // first one later - KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(func_); + KeyMap::Bindings bindings = theTopLevelKeymap().findBindings(*func_); if (!bindings.empty()) return toqstr(bindings.begin()->print(KeySequence::ForGui)); LYXERR(Debug::KBMAP, "No binding for " - << lyxaction.getActionName(func_.action()) - << '(' << func_.argument() << ')'); + << lyxaction.getActionName(func_->action()) + << '(' << func_->argument() << ')'); return QString(); } @@ -285,7 +291,7 @@ private: /// QString label_; /// - FuncRequest func_; + shared_ptr func_;// non-null /// QString submenuname_; /// @@ -319,8 +325,6 @@ public: /// size_t size() const { return items_.size(); } /// - MenuItem const & operator[](size_t) const; - /// const_iterator begin() const { return items_.begin(); } /// const_iterator end() const { return items_.end(); } @@ -350,7 +354,8 @@ public: void expandFloatListInsert(Buffer const * buf); void expandFloatInsert(Buffer const * buf); void expandFlexInsert(Buffer const * buf, InsetLayout::InsetLyXType type); - void expandToc2(Toc const & toc_list, size_t from, size_t to, int depth); + void expandTocSubmenu(std::string const & type, Toc const & toc_list); + void expandToc2(Toc const & toc_list, size_t from, size_t to, int depth, string toc_type); void expandToc(Buffer const * buf); void expandPasteRecent(Buffer const * buf); void expandToolbars(); @@ -363,6 +368,8 @@ public: void expandLanguageSelector(Buffer const * buf); void expandArguments(BufferView const *, bool switcharg = false); void expandCaptions(Buffer const * buf, bool switchcap = false); + void expandEnvironmentSeparators(BufferView const *); + void expandQuotes(BufferView const *); /// ItemList items_; /// @@ -397,7 +404,7 @@ void MenuDefinition::addWithStatusCheck(MenuItem const & i) switch (i.kind()) { case MenuItem::Command: { - FuncStatus status = lyx::getStatus(i.func()); + FuncStatus status = lyx::getStatus(*i.func()); if (status.unknown() || (!status.enabled() && i.optional())) break; items_.push_back(i); @@ -412,8 +419,8 @@ void MenuDefinition::addWithStatusCheck(MenuItem const & i) cit != i.submenu().end(); ++cit) { // Only these kind of items affect the status of the submenu if ((cit->kind() == MenuItem::Command - || cit->kind() == MenuItem::Submenu - || cit->kind() == MenuItem::Help) + || cit->kind() == MenuItem::Submenu + || cit->kind() == MenuItem::Help) && cit->status().enabled()) { enabled = true; break; @@ -450,6 +457,7 @@ void MenuDefinition::read(Lexer & lex) md_custom, md_elements, md_endmenu, + md_exportformat, md_exportformats, md_importformats, md_indices, @@ -474,7 +482,9 @@ void MenuDefinition::read(Lexer & lex) md_arguments, md_switcharguments, md_captions, - md_switchcaptions + md_switchcaptions, + md_env_separators, + md_switchquotes }; LexerKeyword menutags[] = { @@ -488,6 +498,8 @@ void MenuDefinition::read(Lexer & lex) { "documents", md_documents }, { "elements", md_elements }, { "end", md_endmenu }, + { "environmentseparators", md_env_separators }, + { "exportformat", md_exportformat }, { "exportformats", md_exportformats }, { "floatinsert", md_floatinsert }, { "floatlistinsert", md_floatlistinsert }, @@ -508,6 +520,7 @@ void MenuDefinition::read(Lexer & lex) { "submenu", md_submenu }, { "switcharguments", md_switcharguments }, { "switchcaptions", md_switchcaptions }, + { "switchquotes", md_switchquotes }, { "toc", md_toc }, { "toolbars", md_toolbars }, { "updateformats", md_updateformats }, @@ -517,14 +530,10 @@ void MenuDefinition::read(Lexer & lex) lex.pushTable(menutags); lex.setContext("MenuDefinition::read: "); - bool quit = false; - bool optional = false; - - while (lex.isOK() && !quit) { - switch (lex.lex()) { + int md_type = 0; + while (lex.isOK() && md_type != md_endmenu) { + switch (md_type = lex.lex()) { case md_optitem: - optional = true; - // fallback to md_item case md_item: { lex.next(true); docstring const name = translateIfPossible(lex.getDocString()); @@ -534,8 +543,8 @@ void MenuDefinition::read(Lexer & lex) FuncRequest::Origin origin = FuncRequest::MENU; if (name_.startsWith("context-toc-")) origin = FuncRequest::TOC; + bool const optional = (md_type == md_optitem); add(MenuItem(MenuItem::Command, toqstr(name), func, QString(), optional, origin)); - optional = false; break; } @@ -583,6 +592,10 @@ void MenuDefinition::read(Lexer & lex) add(MenuItem(MenuItem::ExportFormats)); break; + case md_exportformat: + add(MenuItem(MenuItem::ExportFormat)); + break; + case md_importformats: add(MenuItem(MenuItem::ImportFormats)); break; @@ -655,22 +668,27 @@ void MenuDefinition::read(Lexer & lex) add(MenuItem(MenuItem::SwitchCaptions)); break; + case md_env_separators: + add(MenuItem(MenuItem::EnvironmentSeparators)); + break; + + case md_switchquotes: + add(MenuItem(MenuItem::SwitchQuotes)); + break; + case md_optsubmenu: - optional = true; - // fallback to md_submenu case md_submenu: { lex.next(true); docstring const mlabel = translateIfPossible(lex.getDocString()); lex.next(true); docstring const mname = lex.getDocString(); + bool const optional = (md_type == md_optsubmenu); add(MenuItem(MenuItem::Submenu, toqstr(mlabel), toqstr(mname), QString(), optional)); - optional = false; break; } case md_endmenu: - quit = true; break; default: @@ -682,16 +700,10 @@ void MenuDefinition::read(Lexer & lex) } -MenuItem const & MenuDefinition::operator[](size_type i) const -{ - return items_[i]; -} - - bool MenuDefinition::hasFunc(FuncRequest const & func) const { for (const_iterator it = begin(), et = end(); it != et; ++it) - if (it->func() == func) + if (*it->func() == func) return true; return false; } @@ -741,7 +753,7 @@ bool MenuDefinition::searchMenu(FuncRequest const & func, docstring_list & names const_iterator m = begin(); const_iterator m_end = end(); for (; m != m_end; ++m) { - if (m->kind() == MenuItem::Command && m->func() == func) { + if (m->kind() == MenuItem::Command && *m->func() == func) { names.push_back(qstring_to_ucs4(m->label())); return true; } @@ -765,11 +777,9 @@ bool MenuDefinition::searchMenu(FuncRequest const & func, docstring_list & names QString limitStringLength(docstring const & str) { size_t const max_item_length = 45; - - if (str.size() > max_item_length) - return toqstr(str.substr(0, max_item_length - 3) + "..."); - - return toqstr(str); + docstring ret = str.substr(0, max_item_length + 1); + support::truncateWithEllipsis(ret, max_item_length); + return toqstr(ret); } @@ -980,6 +990,8 @@ void MenuDefinition::expandDocuments() QString label = toqstr(b.fileName().displayName(20)); if (!b.isClean()) label += "*"; + if (b.notifiesExternalModification()) + label += QChar(0x26a0); if (i < 10) label = QString::number(i) + ". " + label + '|' + QString::number(i); add(MenuItem(MenuItem::Command, label, @@ -997,6 +1009,8 @@ void MenuDefinition::expandDocuments() QString label = toqstr(b->fileName().displayName(20)); if (!b->isClean()) label += "*"; + if (b->notifiesExternalModification()) + label += QChar(0x26a0); if (i < 10) label = QString::number(i) + ". " + label + '|' + QString::number(i); item.submenu().add(MenuItem(MenuItem::Command, label, @@ -1036,8 +1050,7 @@ void MenuDefinition::expandFormats(MenuItem::Kind const kind, Buffer const * buf if (!buf && kind != MenuItem::ImportFormats) return; - typedef vector Formats; - Formats formats; + FormatList formats; FuncCode action = LFUN_NOACTION; switch (kind) { @@ -1058,7 +1071,7 @@ void MenuDefinition::expandFormats(MenuItem::Kind const kind, Buffer const * buf action = LFUN_BUFFER_EXPORT; break; default: - LASSERT(false, /* */); + LATTEST(false); return; } @@ -1073,14 +1086,12 @@ void MenuDefinition::expandFormats(MenuItem::Kind const kind, Buffer const * buf MenuItem item(MenuItem::Submenu, smenue); item.setSubmenu(MenuDefinition(smenue)); - Formats::const_iterator fit = formats.begin(); - Formats::const_iterator end = formats.end(); - for (; fit != end ; ++fit) { - if ((*fit)->dummy()) + for (Format const * f : formats) { + if (f->dummy()) continue; - docstring lab = from_utf8((*fit)->prettyname()); - docstring const scut = from_utf8((*fit)->shortcut()); + docstring lab = f->prettyname(); + docstring const scut = from_utf8(f->shortcut()); docstring const tmplab = lab; if (!scut.empty()) @@ -1097,7 +1108,7 @@ void MenuDefinition::expandFormats(MenuItem::Kind const kind, Buffer const * buf break; case MenuItem::ViewFormats: case MenuItem::UpdateFormats: - if ((*fit)->name() == buf->params().getDefaultOutputFormat()) { + if (f->name() == buf->params().getDefaultOutputFormat()) { docstring lbl = (kind == MenuItem::ViewFormats ? bformat(_("View [%1$s]|V"), label) : bformat(_("Update [%1$s]|U"), label)); @@ -1106,30 +1117,29 @@ void MenuDefinition::expandFormats(MenuItem::Kind const kind, Buffer const * buf } // fall through case MenuItem::ExportFormats: - if (!(*fit)->inExportMenu()) + if (!f->inExportMenu()) continue; break; default: - LASSERT(false, /* */); + // we already asserted earlier in this case + // LATTEST(false); continue; } if (!shortcut.empty()) label += '|' + shortcut; if (view_update) { - if (buf) - item.submenu().addWithStatusCheck(MenuItem(MenuItem::Command, - toqstr(label), FuncRequest(action, (*fit)->name()))); - else - item.submenu().add(MenuItem(MenuItem::Command, toqstr(label), - FuncRequest(action, (*fit)->name()))); + // note that at this point, we know that buf is not null + LATTEST(buf); + item.submenu().addWithStatusCheck(MenuItem(MenuItem::Command, + toqstr(label), FuncRequest(action, f->name()))); } else { if (buf) addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(label), - FuncRequest(action, (*fit)->name()))); + FuncRequest(action, f->name()))); else add(MenuItem(MenuItem::Command, toqstr(label), - FuncRequest(action, (*fit)->name()))); + FuncRequest(action, f->name()))); } } if (view_update) @@ -1199,9 +1209,11 @@ void MenuDefinition::expandFlexInsert( TextClass::InsetLayouts::const_iterator end = insetLayouts.end(); for (; cit != end; ++cit) { if (cit->second.lyxtype() == type) { + if (!cit->second.obsoleted_by().empty()) + continue; docstring label = cit->first; // we remove the "Flex:" prefix, if it is present - if (prefixIs(label, from_utf8("Flex:"))) + if (prefixIs(label, from_ascii("Flex:"))) label = label.substr(5); addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(translateIfPossible(label)), @@ -1209,15 +1221,23 @@ void MenuDefinition::expandFlexInsert( } } // FIXME This is a little clunky. - if (items_.empty() && type == InsetLayout::CUSTOM) + if (items_.empty() && type == InsetLayout::CUSTOM && !buf->hasReadonlyFlag()) add(MenuItem(MenuItem::Help, qt_("No Custom Insets Defined!"))); } -size_t const max_number_of_items = 25; +// Threshold before we stop displaying sub-items alongside items +// (for display purposes). Ideally this should fit on a screen. +size_t const max_number_of_items = 30; +// Size limit for the menu. This is for performance purposes, +// because qt already displays a scrollable menu when necessary. +// Ideally this should be the menu size from which scrollable +// menus become unpractical. +size_t const menu_size_limit = 80; void MenuDefinition::expandToc2(Toc const & toc_list, - size_t from, size_t to, int depth) + size_t from, size_t to, int depth, + string toc_type) { int shortcut_count = 0; @@ -1231,7 +1251,7 @@ void MenuDefinition::expandToc2(Toc const & toc_list, if (to - from <= max_number_of_items) { for (size_t i = from; i < to; ++i) { QString label(4 * max(0, toc_list[i].depth() - depth), ' '); - label += limitStringLength(toc_list[i].str()); + label += limitStringLength(toc_list[i].asString()); if (toc_list[i].depth() == depth) { label += '|'; if (shortcut_count < 9) { @@ -1241,16 +1261,20 @@ void MenuDefinition::expandToc2(Toc const & toc_list, } add(MenuItem(MenuItem::Command, label, FuncRequest(toc_list[i].action()))); + // separator after the menu heading + if (toc_list[i].depth() < depth) + add(MenuItem(MenuItem::Separator)); } } else { size_t pos = from; + size_t size = 1; while (pos < to) { size_t new_pos = pos + 1; while (new_pos < to && toc_list[new_pos].depth() > depth) ++new_pos; QString label(4 * max(0, toc_list[pos].depth() - depth), ' '); - label += limitStringLength(toc_list[pos].str()); + label += limitStringLength(toc_list[pos].asString()); if (toc_list[pos].depth() == depth) { label += '|'; if (shortcut_count < 9) { @@ -1258,16 +1282,22 @@ void MenuDefinition::expandToc2(Toc const & toc_list, label += QString::number(++shortcut_count); } } + if (size >= menu_size_limit) { + FuncRequest f(LFUN_DIALOG_SHOW, "toc " + toc_type); + add(MenuItem(MenuItem::Command, "...", f)); + break; + } if (new_pos == pos + 1) { add(MenuItem(MenuItem::Command, label, FuncRequest(toc_list[pos].action()))); } else { MenuDefinition sub; - sub.expandToc2(toc_list, pos, new_pos, depth + 1); + sub.expandToc2(toc_list, pos, new_pos, depth + 1, toc_type); MenuItem item(MenuItem::Submenu, label); item.setSubmenu(sub); add(item); } + ++size; pos = new_pos; } } @@ -1280,12 +1310,10 @@ void MenuDefinition::expandToc(Buffer const * buf) // all MenuItem constructors and to expandToc2. However, we // know that all the entries in a TOC will be have status_ == // OK, so we avoid this unnecessary overhead (JMarc) - if (!buf) { - add(MenuItem(MenuItem::Info, qt_(""))); + add(MenuItem(MenuItem::Info, qt_("(No Document Open)"))); return; } - // Add an entry for the master doc if this is a child doc Buffer const * const master = buf->masterBuffer(); if (buf != master) { @@ -1296,37 +1324,22 @@ void MenuDefinition::expandToc(Buffer const * buf) } MenuDefinition other_lists; - - FloatList const & floatlist = buf->params().documentClass().floats(); - TocList const & toc_list = buf->tocBackend().tocs(); - TocList::const_iterator cit = toc_list.begin(); - TocList::const_iterator end = toc_list.end(); - for (; cit != end; ++cit) { - // Handle this later - if (cit->first == "tableofcontents") + // In the navigation menu, only add tocs from this document + TocBackend const & backend = buf->tocBackend(); + TocList const & toc_list = backend.tocs(); + for (pair> const & toc : toc_list) { + // Handle table of contents later + if (toc.first == "tableofcontents" || toc.second->empty()) continue; - MenuDefinition submenu; - if (cit->second.size() >= 30) { - FuncRequest f(LFUN_DIALOG_SHOW, "toc " + cit->first); - submenu.add(MenuItem(MenuItem::Command, qt_("Open Navigator..."), f)); - } else { - TocIterator ccit = cit->second.begin(); - TocIterator eend = cit->second.end(); - for (; ccit != eend; ++ccit) { - submenu.add(MenuItem(MenuItem::Command, - limitStringLength(ccit->str()) + '|', - FuncRequest(ccit->action()))); - } - } - - MenuItem item(MenuItem::Submenu, guiName(cit->first, buf->params())); + submenu.expandTocSubmenu(toc.first, *toc.second); + docstring const toc_name = backend.outlinerName(toc.first); + MenuItem item(MenuItem::Submenu, toqstr(toc_name)); item.setSubmenu(submenu); - if (floatlist.typeExist(cit->first) || cit->first == "child") { - // Those two types deserve to be in the main menu. - item.setSubmenu(submenu); + // deserves to be in the main menu? + if (!TocBackend::isOther(toc.first)) add(item); - } else + else other_lists.add(item); } if (!other_lists.empty()) { @@ -1334,20 +1347,32 @@ void MenuDefinition::expandToc(Buffer const * buf) item.setSubmenu(other_lists); add(item); } - // Handle normal TOC - cit = toc_list.find("tableofcontents"); - if (cit == end) + add(MenuItem(MenuItem::Separator)); + TocList::const_iterator cit = toc_list.find("tableofcontents"); + if (cit == toc_list.end()) LYXERR(Debug::GUI, "No table of contents."); else { - if (!cit->second.empty()) - expandToc2(cit->second, 0, cit->second.size(), 0); + if (!cit->second->empty()) + expandToc2(*cit->second, 0, cit->second->size(), 0, + "tableofcontents"); else - add(MenuItem(MenuItem::Info, qt_(""))); + add(MenuItem(MenuItem::Info, qt_("(Empty Table of Contents)"))); } } +void MenuDefinition::expandTocSubmenu(std::string const & type, Toc const & toc) +{ + // "Open outliner..." entry + FuncRequest f(LFUN_DIALOG_SHOW, "toc " + type); + add(MenuItem(MenuItem::Command, qt_("Open Outliner..."), f)); + add(MenuItem(MenuItem::Separator)); + // add entries + expandToc2(toc, 0, toc.size(), 0, type); +} + + void MenuDefinition::expandPasteRecent(Buffer const * buf) { docstring_list const sel = cap::availableSelections(buf); @@ -1387,7 +1412,7 @@ void MenuDefinition::expandToolbars() void MenuDefinition::expandBranches(Buffer const * buf) { - if (!buf) + if (!buf || buf->hasReadonlyFlag()) return; BufferParams const & master_params = buf->masterBuffer()->params(); @@ -1524,10 +1549,11 @@ void MenuDefinition::expandCiteStyles(BufferView const * bv) FuncRequest(LFUN_NOACTION))); return; } - InsetCommand const * citinset = - static_cast(inset); + InsetCitation const * citinset = + static_cast(inset); Buffer const * buf = &bv->buffer(); + BufferParams const & bp = buf->masterParams(); string const cmd = citinset->params().getCmdName(); docstring const & key = citinset->getParam("key"); @@ -1538,32 +1564,85 @@ void MenuDefinition::expandCiteStyles(BufferView const * bv) return; } - docstring const & before = citinset->getParam("before"); - docstring const & after = citinset->getParam("after"); - size_t const n = cmd.size(); - bool const force = cmd[0] == 'C'; - bool const full = cmd[n] == '*'; + bool const force = isUpperCase(cmd[0]); + bool const star = cmd[n] == '*'; vector const keys = getVectorFromString(key); - vector const citeStyleList = buf->params().citeStyles(); - vector citeStrings = - buf->masterBibInfo().getCiteStrings(keys, citeStyleList, bv->buffer(), - false, before, after, from_utf8("dialog")); - - vector::const_iterator cit = citeStrings.begin(); - vector::const_iterator end = citeStrings.end(); + vector const citeStyleList = bp.citeStyles(); + + CitationStyle cs = citinset->getCitationStyle(bp, cmd, citeStyleList); + bool const qualified = cs.hasQualifiedList + && (keys.size() > 1 + || !citinset->getParam("pretextlist").empty() + || !citinset->getParam("posttextlist").empty()); + std::map pres = + citinset->getQualifiedLists(citinset->getParam("pretextlist")); + std::map posts = + citinset->getQualifiedLists(citinset->getParam("posttextlist")); + + CiteItem ci; + ci.textBefore = citinset->getParam("before"); + ci.textAfter = citinset->getParam("after"); + ci.forceUpperCase = force; + ci.Starred = star; + ci.context = CiteItem::Dialog; + ci.max_size = 40; + ci.isQualified = qualified; + ci.pretexts = pres; + ci.posttexts = posts; + BiblioInfo::CiteStringMap citeStrings = + buf->masterBibInfo().getCiteStrings(keys, citeStyleList, bv->buffer(), ci); + + BiblioInfo::CiteStringMap::const_iterator cit = citeStrings.begin(); + BiblioInfo::CiteStringMap::const_iterator end = citeStrings.end(); for (int ii = 1; cit != end; ++cit, ++ii) { - docstring label = *cit; + docstring label = cit->second; CitationStyle cs = citeStyleList[ii - 1]; cs.forceUpperCase &= force; - cs.fullAuthorList &= full; + cs.hasStarredVersion &= star; addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(label), FuncRequest(LFUN_INSET_MODIFY, "changetype " + from_utf8(citationStyleToString(cs))))); } + + if (cs.hasStarredVersion) { + docstring starred = _("All authors|h"); + // Check if we have a custom string/tooltip for the starred version + if (!cs.stardesc.empty()) { + string val = + bp.documentClass().getCiteMacro(buf->params().citeEngineType(), cs.stardesc); + if (!val.empty()) + starred = translateIfPossible(from_utf8(val)); + // Transform qt-style accelerators to menu-style + int const amps = count_char(starred, '&'); + if (amps > 0) { + if (amps > 1) + starred = subst(starred, from_ascii("&&"), from_ascii("<:amp:>")); + size_t n = starred.find('&'); + char_type accel = char_type(); + if (n != docstring::npos && n < starred.size() - 1) + accel = starred[n + 1]; + starred = subst(starred, from_ascii("&"), from_ascii("")); + if (amps > 1) + starred = subst(starred, from_ascii("<:amp:>"), from_ascii("&&")); + if (accel != char_type()) + starred = starred + '|' + accel; + } + } + add(MenuItem(MenuItem::Separator)); + addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(starred), + FuncRequest(LFUN_INSET_MODIFY, "toggleparam star"))); + } + + if (cs.forceUpperCase) { + if (!cs.hasStarredVersion) + add(MenuItem(MenuItem::Separator)); + addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(_("Force upper case|u")), + FuncRequest(LFUN_INSET_MODIFY, "toggleparam casing"))); + } } @@ -1605,47 +1684,37 @@ void MenuDefinition::expandCaptions(Buffer const * buf, bool switchcap) if (!buf) return; - vector caps; DocumentClass const & dc = buf->params().documentClass(); - TextClass::InsetLayouts::const_iterator lit = dc.insetLayouts().begin(); - TextClass::InsetLayouts::const_iterator len = dc.insetLayouts().end(); - for (; lit != len; ++lit) { - if (prefixIs(lit->first, from_ascii("Caption:"))) - caps.push_back(lit->first); + vector< pair > caps; + for (pair const & il : dc.insetLayouts()) { + docstring instype; + docstring const type = split(il.first, instype, ':'); + if (instype == from_ascii("Caption")) { + // skip forbidden caption types + FuncRequest const cmd = switchcap + ? FuncRequest(LFUN_INSET_MODIFY, from_ascii("changetype ") + type) + : FuncRequest(LFUN_CAPTION_INSERT, type); + if (getStatus(cmd).enabled()) + caps.push_back(make_pair(type, cmd)); + } } if (caps.empty() || (switchcap && caps.size() == 1)) return; if (caps.size() == 1) { - docstring dummy; - docstring const type = split(*caps.begin(), dummy, ':'); - add(MenuItem(MenuItem::Command, qt_("Caption"), - FuncRequest(LFUN_CAPTION_INSERT, translateIfPossible(type)))); + add(MenuItem(MenuItem::Command, qt_("Caption"), caps.front().second)); return; } MenuDefinition captions; - - vector::const_iterator cit = caps.begin(); - vector::const_iterator end = caps.end(); - - for (int ii = 1; cit != end; ++cit, ++ii) { - docstring dummy; - docstring const type = split(*cit, dummy, ':'); + for (pair const & cap : caps) { + docstring const type = cap.first; docstring const trtype = translateIfPossible(type); docstring const cmitem = bformat(_("Caption (%1$s)"), trtype); - // make menu item optional, otherwise we would also see - // forbidden caption types if (switchcap) - addWithStatusCheck(MenuItem(MenuItem::Command, toqstr(cmitem), - FuncRequest(LFUN_INSET_MODIFY, - from_ascii("changetype ") - + type), QString(), true)); + add(MenuItem(MenuItem::Command, toqstr(cmitem), cap.second)); else - captions.addWithStatusCheck(MenuItem(MenuItem::Command, - toqstr(trtype), - FuncRequest(LFUN_CAPTION_INSERT, - type), QString(), true)); + captions.add(MenuItem(MenuItem::Command, toqstr(trtype), cap.second)); } if (!captions.empty()) { MenuItem item(MenuItem::Submenu, qt_("Caption")); @@ -1654,6 +1723,173 @@ void MenuDefinition::expandCaptions(Buffer const * buf, bool switchcap) } } + +void MenuDefinition::expandQuotes(BufferView const * bv) +{ + if (!bv) + return; + + if (!bv->cursor().inTexted()) + return; + + Inset const * inset = bv->cursor().nextInset(); + if (!inset || inset->lyxCode() != QUOTE_CODE) { + add(MenuItem(MenuItem::Command, + qt_("No Quote in Scope!"), + FuncRequest(LFUN_NOACTION))); + return; + } + InsetQuotes const * qinset = + static_cast(inset); + + map styles = quoteparams.getTypes(); + string const qtype = qinset->getType(); + + map::const_iterator qq = styles.begin(); + map::const_iterator end = styles.end(); + + MenuDefinition aqs; + + BufferParams const & bp = bv->buffer().masterBuffer()->params(); + + // The global setting + InsetQuotesParams::QuoteStyle globalqs = bp.quotes_style; + char const globalqsc = quoteparams.getStyleChar(globalqs); + + // The current language's default + InsetQuotesParams::QuoteStyle langdefqs = + bp.getQuoteStyle(bv->cursor().current_font.language()->quoteStyle()); + char const langqs = quoteparams.getStyleChar(langdefqs); + + bool main_global_qs = false; + bool main_langdef_qs = false; + bool main_dynamic_qs = false; + docstring const subcmd = from_ascii("changetype "); + docstring const wildcards = from_ascii(".."); + // Add the items + // First the top level menu (all glyphs of the current style) ... + // Begin with dynamic (if they are current style), + if (qtype[0] == 'x') { + FuncRequest cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + from_ascii("xld")); + docstring desc = bformat(_("%1$s (dynamic)"), + quoteparams.getShortGuiLabel(globalqsc + from_ascii("ld"))); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + from_ascii("xls")); + desc = bformat(_("%1$s (dynamic)"), + quoteparams.getShortGuiLabel(globalqsc + from_ascii("ls"))); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + from_ascii("xrd")); + desc = bformat(_("%1$s (dynamic)"), + quoteparams.getShortGuiLabel(globalqsc + from_ascii("rd"))); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + from_ascii("xrs")); + desc = bformat(_("%1$s (dynamic)"), + quoteparams.getShortGuiLabel(globalqsc + from_ascii("rs"))); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + main_dynamic_qs = true; + } + // now traverse through the static styles ... + for (; qq != end; ++qq) { + docstring const style = from_ascii(qq->first); + bool langdef = (style[0] == langqs); + bool globaldef = (style[0] == globalqsc); + + if (prefixIs(style, qtype[0])) { + FuncRequest cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + style); + docstring const desc = quoteparams.getShortGuiLabel(style); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + main_global_qs = globaldef; + main_langdef_qs = langdef; + } + else if (!langdef && !globaldef && suffixIs(style, from_ascii("ld"))) { + docstring const desc = + quoteparams.getGuiLabel(quoteparams.getQuoteStyle(to_ascii(style))); + FuncRequest cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + style[0] + ".."); + aqs.add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + } + } + + add(MenuItem(MenuItem::Separator)); + + bool display_static = false; + // ... then potentially items to reset to the defaults and to dynamic style ... + if (!main_dynamic_qs && globalqsc != 'x') { + FuncRequest cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + 'x' + wildcards); + docstring const desc = bformat(_("Use dynamic quotes (%1$s)|d"), + quoteparams.getGuiLabel(globalqs)); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + display_static = true; + } + if (!main_global_qs && langdefqs != globalqs) { + docstring const variant = main_dynamic_qs ? _("dynamic[[Quotes]]") : _("static[[Quotes]]"); + FuncRequest cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + globalqsc + wildcards); + docstring const desc = bformat(_("Reset to document default (%1$s, %2$s)|o"), + quoteparams.getGuiLabel(globalqs), variant); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + } + if (!main_langdef_qs) { + FuncRequest cmd = FuncRequest(LFUN_INSET_MODIFY, subcmd + globalqsc + wildcards); + docstring const desc = (main_dynamic_qs || display_static) + ? bformat(_("Reset to language default (%1$s, %2$s)|l"), + quoteparams.getGuiLabel(langdefqs), _("static[[Quotes]]")) + : bformat(_("Reset to language default (%1$s)|l"), + quoteparams.getGuiLabel(langdefqs)); + add(MenuItem(MenuItem::Command, toqstr(desc), cmd)); + } + + add(MenuItem(MenuItem::Separator)); + + // ... and a subitem with the rest + MenuItem item(MenuItem::Submenu, qt_("Change Style|y")); + item.setSubmenu(aqs); + add(item); +} + + +void MenuDefinition::expandEnvironmentSeparators(BufferView const * bv) +{ + if (!bv) + return; + Text const * text = bv->cursor().text(); + // no paragraphs and no separators exist in math + if (!text) + return; + + pit_type pit = bv->cursor().selBegin().pit(); + Paragraph const & par = text->getPar(pit); + docstring const curlayout = par.layout().name(); + docstring outerlayout; + depth_type current_depth = par.params().depth(); + // check if we have an environment in our nesting hierarchy + Paragraph cpar = par; + while (true) { + if (pit == 0 || cpar.params().depth() == 0) + break; + --pit; + cpar = text->getPar(pit); + if (cpar.params().depth() < current_depth + && cpar.layout().isEnvironment()) { + outerlayout = cpar.layout().name(); + current_depth = cpar.params().depth(); + } + } + if (par.layout().isEnvironment()) { + docstring const label = + bformat(_("Start New Environment (%1$s)"), + translateIfPossible(curlayout)); + add(MenuItem(MenuItem::Command, toqstr(label), + FuncRequest(LFUN_ENVIRONMENT_SPLIT))); + } + if (!outerlayout.empty()) { + docstring const label = + bformat(_("Start New Parent Environment (%1$s)"), + translateIfPossible(outerlayout)); + add(MenuItem(MenuItem::Command, toqstr(label), + FuncRequest(LFUN_ENVIRONMENT_SPLIT, + from_ascii("outer")))); + } +} + } // namespace anon @@ -1665,7 +1901,7 @@ struct Menu::Impl { /// populates the menu or one of its submenu /// This is used as a recursive function - void populate(QMenu & qMenu, MenuDefinition const & menu); + void populate(QMenu * qMenu, MenuDefinition const & menu); /// Only needed for top level menus. MenuDefinition * top_level_menu; @@ -1698,7 +1934,7 @@ static QString label(MenuItem const & mi) return label; } -void Menu::Impl::populate(QMenu & qMenu, MenuDefinition const & menu) +void Menu::Impl::populate(QMenu * qMenu, MenuDefinition const & menu) { LYXERR(Debug::GUI, "populating menu " << menu.name()); if (menu.empty()) { @@ -1706,24 +1942,29 @@ void Menu::Impl::populate(QMenu & qMenu, MenuDefinition const & menu) return; } LYXERR(Debug::GUI, " ***** menu entries " << menu.size()); - MenuDefinition::const_iterator m = menu.begin(); - MenuDefinition::const_iterator end = menu.end(); - for (; m != end; ++m) { - if (m->kind() == MenuItem::Separator) - qMenu.addSeparator(); - else if (m->kind() == MenuItem::Submenu) { - QMenu * subMenu = qMenu.addMenu(label(*m)); - populate(*subMenu, m->submenu()); - subMenu->setEnabled(m->status().enabled()); - } else { - // we have a MenuItem::Command - qMenu.addAction(new Action(view, QIcon(), label(*m), - m->func(), m->tooltip(), &qMenu)); + for (MenuItem const & m : menu) + switch (m.kind()) { + case MenuItem::Separator: + qMenu->addSeparator(); + break; + case MenuItem::Submenu: { + QMenu * subMenu = qMenu->addMenu(label(m)); + populate(subMenu, m.submenu()); + subMenu->setEnabled(!subMenu->isEmpty()); + break; + } + case MenuItem::Command: + default: + // FIXME: A previous comment assured that MenuItem::Command was the + // only possible case in practice, but this is wrong. It would be + // good to document which cases are actually treated here. + qMenu->addAction(new Action(m.func(), QIcon(), label(m), + m.tooltip(), qMenu)); + break; } - } } -#if defined(Q_WS_WIN) && (QT_VERSION >= 0x040600) +#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)) && (QT_VERSION >= 0x040600) class AlwaysMnemonicStyle : public QProxyStyle { public: int styleHint(StyleHint hint, const QStyleOption *opt = 0, const QWidget *widget = 0, @@ -1743,7 +1984,7 @@ public: Menu::Menu(GuiView * gv, QString const & name, bool top_level, bool keyboard) : QMenu(gv), d(new Menu::Impl) { -#if defined(Q_WS_WIN) && (QT_VERSION >= 0x040600) +#if (defined(Q_OS_WIN) || defined(Q_CYGWIN_WIN)) && (QT_VERSION >= 0x040600) if (keyboard) setStyle(new AlwaysMnemonicStyle); #else @@ -1798,13 +2039,14 @@ struct Menus::Impl { /** The entries with the following kind are expanded to a sequence of Command MenuItems: Lastfiles, Documents, ViewFormats, ExportFormats, UpdateFormats, Branches, - Indices, Arguments, SwitchArguments, Captions, SwitchCaptions + Indices, Arguments, SwitchArguments, Captions, SwitchCaptions, + EnvironmentSeparators */ void expand(MenuDefinition const & frommenu, MenuDefinition & tomenu, BufferView const *) const; /// Initialize specific MACOS X menubar - void macxMenuBarInit(GuiView * view, QMenuBar * qmb); + void macxMenuBarInit(QMenuBar * qmb); /// Mac special menu. /** This defines a menu whose entries list the FuncRequests @@ -1854,7 +2096,7 @@ MenuDefinition Menus::Impl::mac_special_menu_; that this menubar will be used also when one of LyX' dialogs has focus. (JMarc) */ -void Menus::Impl::macxMenuBarInit(GuiView * view, QMenuBar * qmb) +void Menus::Impl::macxMenuBarInit(QMenuBar * qmb) { /* Since Qt 4.2, the qt/mac menu code has special code for specifying the role of a menu entry. However, it does not @@ -1877,18 +2119,22 @@ void Menus::Impl::macxMenuBarInit(GuiView * view, QMenuBar * qmb) QAction::MenuRole role; }; - static MacMenuEntry entries[] = { + static const MacMenuEntry entries[] = { {LFUN_DIALOG_SHOW, "aboutlyx", "About LyX", QAction::AboutRole}, {LFUN_DIALOG_SHOW, "prefs", "Preferences", QAction::PreferencesRole}, - /* {LFUN_RECONFIGURE, "", "Reconfigure", - QAction::ApplicationSpecificRole}, */ +#if !(defined(QT_MAC_USE_COCOA) || (QT_VERSION >= 0x050000)) + /* This doesn't work with Cocoa. */ + {LFUN_RECONFIGURE, "", "Reconfigure", + QAction::ApplicationSpecificRole}, +#endif {LFUN_LYX_QUIT, "", "Quit LyX", QAction::QuitRole} }; const size_t num_entries = sizeof(entries) / sizeof(entries[0]); const bool first_call = mac_special_menu_.empty(); + LYXERR(Debug::GUI, "Creating Mac OS X special menu bar"); // the special menu for Menus. Fill it up only once. if (first_call) { for (size_t i = 0 ; i < num_entries ; ++i) { @@ -1902,22 +2148,13 @@ void Menus::Impl::macxMenuBarInit(GuiView * view, QMenuBar * qmb) // add the entries to a QMenu that will eventually be empty // and therefore invisible. QMenu * qMenu = qmb->addMenu("special"); - MenuDefinition::const_iterator cit = mac_special_menu_.begin(); - MenuDefinition::const_iterator end = mac_special_menu_.end(); - for (size_t i = 0 ; cit != end ; ++cit, ++i) { -#if defined(QT_MAC_USE_COCOA) && (QT_MAC_USE_COCOA > 0) - if (first_call || entries[i].role != QAction::ApplicationSpecificRole) { - Action * action = new Action(view, QIcon(), cit->label(), - cit->func(), QString(), qMenu); - action->setMenuRole(entries[i].role); - qMenu->addAction(action); - } -#else - Action * action = new Action(view, QIcon(), cit->label(), - cit->func(), QString(), qMenu); + size_t i = 0; + for (MenuItem const & m : mac_special_menu_) { + Action * action = new Action(m.func(), QIcon(), m.label(), + QString(), qMenu); action->setMenuRole(entries[i].role); qMenu->addAction(action); -#endif + ++i; } } @@ -1951,6 +2188,19 @@ void Menus::Impl::expand(MenuDefinition const & frommenu, tomenu.expandFormats(cit->kind(), buf); break; + case MenuItem::ExportFormat: { + if (!buf) + break; + string const format = buf->params().getDefaultOutputFormat(); + Format const * f = theFormats().getFormat(format); + docstring const name = f ? f->prettyname() : from_utf8(format); + docstring const label = bformat(_("Export [%1$s]|E"), name); + MenuItem item(MenuItem::Command, toqstr(label), + FuncRequest(LFUN_BUFFER_EXPORT)); + tomenu.addWithStatusCheck(item); + break; + } + case MenuItem::CharStyles: tomenu.expandFlexInsert(buf, InsetLayout::CHARSTYLE); break; @@ -2035,6 +2285,14 @@ void Menus::Impl::expand(MenuDefinition const & frommenu, tomenu.expandCaptions(buf, true); break; + case MenuItem::EnvironmentSeparators: + tomenu.expandEnvironmentSeparators(bv); + break; + + case MenuItem::SwitchQuotes: + tomenu.expandQuotes(bv); + break; + case MenuItem::Submenu: { MenuItem item(*cit); item.setSubmenu(MenuDefinition(cit->submenuname())); @@ -2050,7 +2308,7 @@ void Menus::Impl::expand(MenuDefinition const & frommenu, break; case MenuItem::Command: - if (!mac_special_menu_.hasFunc(cit->func())) + if (!mac_special_menu_.hasFunc(*cit->func())) tomenu.addWithStatusCheck(*cit); } } @@ -2075,9 +2333,10 @@ MenuDefinition const & Menus::Impl::getMenu(QString const & name) const { const_iterator cit = find_if(menulist_.begin(), menulist_.end(), MenuNamesEqual(name)); - if (cit == menulist_.end()) + if (cit == menulist_.end()) { LYXERR0("No submenu named " << name); - LASSERT(cit != menulist_.end(), /**/); + LASSERT(false, { static const MenuDefinition m; return m; }); + } return (*cit); } @@ -2086,9 +2345,10 @@ MenuDefinition & Menus::Impl::getMenu(QString const & name) { iterator it = find_if(menulist_.begin(), menulist_.end(), MenuNamesEqual(name)); - if (it == menulist_.end()) + if (it == menulist_.end()) { LYXERR0("No submenu named " << name); - LASSERT(it != menulist_.end(), /**/); + LASSERT(false, { static MenuDefinition m; return m; }); + } return (*it); } @@ -2104,7 +2364,7 @@ Menus::Menus() : d(new Impl) {} Menus::~Menus() { - delete d; + delete d; } @@ -2179,17 +2439,19 @@ bool Menus::searchMenu(FuncRequest const & func, void Menus::fillMenuBar(QMenuBar * qmb, GuiView * view, bool initial) { if (initial) { -#ifdef Q_WS_MACX +#ifdef Q_OS_MAC // setup special mac specific menu items, but only do this // the first time a QMenuBar is created. Otherwise Qt will // create duplicate items in the application menu. It seems // that Qt does not remove them when the QMenubar is cleared. - LYXERR(Debug::GUI, "Creating Mac OS X special menu bar"); - d->macxMenuBarInit(view, qmb); + d->macxMenuBarInit(qmb); #endif } else { // Clear all menubar contents before filling it. qmb->clear(); +#if (QT_VERSION >= 0x050000 && defined(Q_OS_MAC)) + d->macxMenuBarInit(qmb); +#endif } LYXERR(Debug::GUI, "populating menu bar" << d->menubar_.name()); @@ -2229,6 +2491,14 @@ void Menus::fillMenuBar(QMenuBar * qmb, GuiView * view, bool initial) Menu * menu = new Menu(view, m->submenuname(), true); menu->setTitle(label(*m)); + +#if defined(Q_OS_MAC) && (defined(QT_MAC_USE_COCOA) || (QT_VERSION >= 0x050000)) + // On Mac OS with QT/cocoa, the menu is not displayed if there is no action + // so we create a temporary one here + QAction * action = new QAction(menu); + menu->addAction(action); +#endif + qmb->addMenu(menu); d->name_map_[view][name] = menu; @@ -2277,7 +2547,7 @@ void Menus::updateMenu(Menu * qmenu) if (qmenu->d->view) bv = qmenu->d->view->currentBufferView(); d->expand(fromLyxMenu, *qmenu->d->top_level_menu, bv); - qmenu->d->populate(*qmenu, *qmenu->d->top_level_menu); + qmenu->d->populate(qmenu, *qmenu->d->top_level_menu); }