3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Lars Gullik Bjønnes
7 * \author Jean-Marc Lasgouttes
8 * \author Angus Leeming
10 * \author André Pönitz
12 * Full author contact details are available in file CREDITS.
17 #include "TextClass.h"
19 #include "LayoutFile.h"
20 #include "CiteEnginesList.h"
24 #include "FloatList.h"
28 #include "ModuleList.h"
30 #include "frontends/alert.h"
32 #include "support/lassert.h"
33 #include "support/debug.h"
34 #include "support/ExceptionMessage.h"
35 #include "support/FileName.h"
36 #include "support/filetools.h"
37 #include "support/gettext.h"
38 #include "support/lstrings.h"
39 #include "support/os.h"
40 #include "support/TempFile.h"
51 using namespace lyx::support;
55 // Keep the changes documented in the Customization manual.
57 // If you change this format, then you MUST also make sure that
58 // your changes do not invalidate the hardcoded layout file in
59 // LayoutFile.cpp. Additions will never do so, but syntax changes
60 // could. See LayoutFileList::addEmptyClass() and, especially, the
61 // definition of the layoutpost string.
62 // You should also run the development/tools/updatelayouts.py script,
63 // to update the format of all of our layout files.
65 int const LAYOUT_FORMAT = 68; //spitz: New layout tag AddToCiteEngine
68 // Layout format for the current lyx file format. Controls which format is
69 // targeted by Local Layout > Convert. In master, equal to LAYOUT_FORMAT.
70 int const LYXFILE_LAYOUT_FORMAT = LAYOUT_FORMAT;
75 class LayoutNamesEqual : public unary_function<Layout, bool> {
77 LayoutNamesEqual(docstring const & name)
80 bool operator()(Layout const & c) const
82 return c.name() == name_;
89 bool layout2layout(FileName const & filename, FileName const & tempfile,
90 int const format = LAYOUT_FORMAT)
92 FileName const script = libFileSearch("scripts", "layout2layout.py");
94 LYXERR0("Could not find layout conversion "
95 "script layout2layout.py.");
99 ostringstream command;
100 command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
102 << ' ' << quoteName(filename.toFilesystemEncoding())
103 << ' ' << quoteName(tempfile.toFilesystemEncoding());
104 string const command_str = command.str();
106 LYXERR(Debug::TCLASS, "Running `" << command_str << '\'');
108 cmd_ret const ret = runCommand(command_str);
109 if (ret.first != 0) {
110 if (format == LAYOUT_FORMAT)
111 LYXERR0("Conversion of layout with layout2layout.py has failed.");
118 string translateReadType(TextClass::ReadType rt)
121 case TextClass::BASECLASS:
123 case TextClass::MERGE:
125 case TextClass::MODULE:
126 return "module file";
127 case TextClass::CITE_ENGINE:
128 return "cite engine";
129 case TextClass::VALIDATION:
139 // This string should not be translated here,
140 // because it is a layout identifier.
141 docstring const TextClass::plain_layout_ = from_ascii(N_("Plain Layout"));
144 /////////////////////////////////////////////////////////////////////////
148 /////////////////////////////////////////////////////////////////////////
150 TextClass::TextClass()
151 : loaded_(false), tex_class_avail_(false),
152 opt_enginetype_("authoryear|numerical"), opt_fontsize_("10|11|12"),
153 opt_pagestyle_("empty|plain|headings|fancy"), pagestyle_("default"),
154 columns_(1), sides_(OneSide), secnumdepth_(3), tocdepth_(3),
155 outputType_(LATEX), outputFormat_("latex"), has_output_format_(false),
156 defaultfont_(sane_font),
157 titletype_(TITLE_COMMAND_AFTER), titlename_("maketitle"),
158 min_toclevel_(0), max_toclevel_(0), maxcitenames_(2),
159 cite_full_author_list_(true)
164 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
166 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
167 if (!lay.read(lexrc, *this)) {
168 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
172 lay.resfont = lay.font;
173 lay.resfont.realize(defaultfont_);
174 lay.reslabelfont = lay.labelfont;
175 lay.reslabelfont.realize(defaultfont_);
176 return true; // no errors
215 TC_ADDTOHTMLPREAMBLE,
235 LexerKeyword textClassTags[] = {
236 { "addtociteengine", TC_ADDTOCITEENGINE },
237 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
238 { "addtohtmlstyles", TC_ADDTOHTMLSTYLES },
239 { "addtopreamble", TC_ADDTOPREAMBLE },
240 { "citeengine", TC_CITEENGINE },
241 { "citeenginetype", TC_CITEENGINETYPE },
242 { "citeformat", TC_CITEFORMAT },
243 { "citeframework", TC_CITEFRAMEWORK },
244 { "classoptions", TC_CLASSOPTIONS },
245 { "columns", TC_COLUMNS },
246 { "counter", TC_COUNTER },
247 { "defaultbiblio", TC_DEFAULTBIBLIO },
248 { "defaultfont", TC_DEFAULTFONT },
249 { "defaultmodule", TC_DEFAULTMODULE },
250 { "defaultstyle", TC_DEFAULTSTYLE },
251 { "excludesmodule", TC_EXCLUDESMODULE },
252 { "float", TC_FLOAT },
253 { "format", TC_FORMAT },
254 { "fullauthorlist", TC_FULLAUTHORLIST },
255 { "htmlpreamble", TC_HTMLPREAMBLE },
256 { "htmlstyles", TC_HTMLSTYLES },
257 { "htmltocsection", TC_HTMLTOCSECTION },
258 { "ifcounter", TC_IFCOUNTER },
259 { "input", TC_INPUT },
260 { "insetlayout", TC_INSETLAYOUT },
261 { "leftmargin", TC_LEFTMARGIN },
262 { "maxcitenames", TC_MAXCITENAMES },
263 { "modifystyle", TC_MODIFYSTYLE },
264 { "nocounter", TC_NOCOUNTER },
265 { "nofloat", TC_NOFLOAT },
266 { "noinsetlayout", TC_NOINSETLAYOUT },
267 { "nostyle", TC_NOSTYLE },
268 { "outlinername", TC_OUTLINERNAME },
269 { "outputformat", TC_OUTPUTFORMAT },
270 { "outputtype", TC_OUTPUTTYPE },
271 { "packageoptions", TC_PKGOPTS },
272 { "pagestyle", TC_PAGESTYLE },
273 { "preamble", TC_PREAMBLE },
274 { "provides", TC_PROVIDES },
275 { "providesmodule", TC_PROVIDESMODULE },
276 { "providestyle", TC_PROVIDESTYLE },
277 { "requires", TC_REQUIRES },
278 { "rightmargin", TC_RIGHTMARGIN },
279 { "secnumdepth", TC_SECNUMDEPTH },
280 { "sides", TC_SIDES },
281 { "style", TC_STYLE },
282 { "titlelatexname", TC_TITLELATEXNAME },
283 { "titlelatextype", TC_TITLELATEXTYPE },
284 { "tocdepth", TC_TOCDEPTH }
290 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
292 LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT);
293 TempFile tmp("convertXXXXXX.layout");
294 FileName const tempfile = tmp.name();
295 bool success = layout2layout(filename, tempfile);
297 success = readWithoutConv(tempfile, rt) == OK;
302 std::string TextClass::convert(std::string const & str)
304 TempFile tmp1("localXXXXXX.layout");
305 FileName const fn = tmp1.name();
306 ofstream os(fn.toFilesystemEncoding().c_str());
309 TempFile tmp2("convert_localXXXXXX.layout");
310 FileName const tempfile = tmp2.name();
311 bool success = layout2layout(fn, tempfile, LYXFILE_LAYOUT_FORMAT);
314 ifstream is(tempfile.toFilesystemEncoding().c_str());
326 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
328 if (!filename.isReadableFile()) {
329 lyxerr << "Cannot read layout file `" << filename << "'."
334 LYXERR(Debug::TCLASS, "Reading " + translateReadType(rt) + ": " +
335 to_utf8(makeDisplayPath(filename.absFileName())));
337 // Define the plain layout used in table cells, ert, etc. Note that
338 // we do this before loading any layout file, so that classes can
339 // override features of this layout if they should choose to do so.
340 if (rt == BASECLASS && !hasLayout(plain_layout_))
341 layoutlist_.push_back(createBasicLayout(plain_layout_));
343 Lexer lexrc(textClassTags);
344 lexrc.setFile(filename);
345 ReturnValues retval = read(lexrc, rt);
347 LYXERR(Debug::TCLASS, "Finished reading " + translateReadType(rt) + ": " +
348 to_utf8(makeDisplayPath(filename.absFileName())));
354 bool TextClass::read(FileName const & filename, ReadType rt)
356 ReturnValues const retval = readWithoutConv(filename, rt);
357 if (retval != FORMAT_MISMATCH)
360 bool const worx = convertLayoutFormat(filename, rt);
362 LYXERR0 ("Unable to convert " << filename <<
363 " to format " << LAYOUT_FORMAT);
368 TextClass::ReturnValues TextClass::validate(std::string const & str)
371 return tc.read(str, VALIDATION);
375 TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt)
377 Lexer lexrc(textClassTags);
378 istringstream is(str);
380 ReturnValues retval = read(lexrc, rt);
382 if (retval != FORMAT_MISMATCH)
385 // write the layout string to a temporary file
386 TempFile tmp("TextClass_read");
387 FileName const tempfile = tmp.name();
388 ofstream os(tempfile.toFilesystemEncoding().c_str());
390 LYXERR0("Unable to create temporary file");
396 // now try to convert it to LAYOUT_FORMAT
397 if (!convertLayoutFormat(tempfile, rt)) {
398 LYXERR0("Unable to convert internal layout information to format "
407 // Reads a textclass structure from file.
408 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
413 // The first usable line should be
414 // Format LAYOUT_FORMAT
415 if (lexrc.lex() != TC_FORMAT || !lexrc.next()
416 || lexrc.getInteger() != LAYOUT_FORMAT)
417 return FORMAT_MISMATCH;
421 while (lexrc.isOK() && !error) {
422 int le = lexrc.lex();
425 case Lexer::LEX_FEOF:
428 case Lexer::LEX_UNDEF:
429 lexrc.printError("Unknown TextClass tag `$$Token'");
437 // used below to track whether we are in an IfStyle or IfCounter tag.
438 bool modifystyle = false;
439 bool providestyle = false;
440 bool ifcounter = false;
442 switch (static_cast<TextClassTags>(le)) {
446 lexrc.printError("Duplicate Format directive");
449 case TC_OUTPUTFORMAT:
451 outputFormat_ = lexrc.getString();
452 has_output_format_ = true;
457 readOutputType(lexrc);
458 switch(outputType_) {
460 outputFormat_ = "latex";
463 outputFormat_ = "docbook";
466 outputFormat_ = "literate";
471 case TC_INPUT: // Include file
474 string const inc = lexrc.getString();
475 if (!path().empty() && (prefixIs(inc, "./") ||
476 prefixIs(inc, "../")))
477 tmp = fileSearch(path(), inc, "layout");
479 tmp = libFileSearch("layouts", inc,
483 lexrc.printError("Could not find input file: " + inc);
485 } else if (!read(tmp, MERGE)) {
486 lexrc.printError("Error reading input file: " + tmp.absFileName());
492 case TC_DEFAULTSTYLE:
494 docstring const name = from_utf8(subst(lexrc.getString(),
496 defaultlayout_ = name;
503 case TC_PROVIDESTYLE:
504 // if modifystyle is true, then we got here by falling through
505 // so we are not in an ProvideStyle block
511 lexrc.printError("No name given for style: `$$Token'.");
515 docstring const name = from_utf8(subst(lexrc.getString(),
518 string s = "Could not read name for style: `$$Token' "
519 + lexrc.getString() + " is probably not valid UTF-8!";
522 // Since we couldn't read the name, we just scan the rest
523 // of the style and discard it.
524 error = !readStyle(lexrc, lay);
528 bool const have_layout = hasLayout(name);
530 // If the layout already exists, then we want to add it to
531 // the existing layout, as long as we are not in an ProvideStyle
533 if (have_layout && !providestyle) {
534 Layout & lay = operator[](name);
535 error = !readStyle(lexrc, lay);
537 // If the layout does not exist, then we want to create a new
538 // one, but not if we are in a ModifyStyle block.
539 else if (!have_layout && !modifystyle) {
541 layout.setName(name);
542 error = !readStyle(lexrc, layout);
544 layoutlist_.push_back(layout);
546 if (defaultlayout_.empty()) {
547 // We do not have a default layout yet, so we choose
548 // the first layout we encounter.
549 defaultlayout_ = name;
552 // There are two ways to get here:
553 // (i) The layout exists but we are in an ProvideStyle block
554 // (ii) The layout doesn't exist, but we are in an ModifyStyle
556 // Either way, we just scan the rest and discard it
559 // signal to coverity that we do not care about the result
560 (void)readStyle(lexrc, lay);
567 docstring const style = from_utf8(subst(lexrc.getString(),
569 if (!deleteLayout(style))
570 lyxerr << "Cannot delete style `"
571 << to_utf8(style) << '\'' << endl;
575 case TC_NOINSETLAYOUT:
577 docstring const style = from_utf8(subst(lexrc.getString(),
579 if (!deleteInsetLayout(style))
580 LYXERR0("Style `" << style << "' cannot be removed\n"
581 "because it was not found!");
587 columns_ = lexrc.getInteger();
592 switch (lexrc.getInteger()) {
593 case 1: sides_ = OneSide; break;
594 case 2: sides_ = TwoSides; break;
596 lyxerr << "Impossible number of page"
597 " sides, setting to one."
607 pagestyle_ = rtrim(lexrc.getString());
611 defaultfont_ = lyxRead(lexrc);
612 if (!defaultfont_.resolved()) {
613 lexrc.printError("Warning: defaultfont should "
614 "be fully instantiated!");
615 defaultfont_.realize(sane_font);
621 secnumdepth_ = lexrc.getInteger();
626 tocdepth_ = lexrc.getInteger();
629 // First step to support options
630 case TC_CLASSOPTIONS:
631 readClassOptions(lexrc);
635 preamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
638 case TC_HTMLPREAMBLE:
639 htmlpreamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
643 htmlstyles_ = lexrc.getLongString(from_ascii("EndStyles"));
646 case TC_HTMLTOCSECTION:
647 html_toc_section_ = from_utf8(trim(lexrc.getString()));
650 case TC_ADDTOPREAMBLE:
651 preamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
654 case TC_ADDTOHTMLPREAMBLE:
655 htmlpreamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
658 case TC_ADDTOHTMLSTYLES:
659 htmlstyles_ += lexrc.getLongString(from_ascii("EndStyles"));
664 string const feature = lexrc.getString();
666 if (lexrc.getInteger())
667 provides_.insert(feature);
669 provides_.erase(feature);
675 vector<string> const req
676 = getVectorFromString(lexrc.getString());
677 requires_.insert(req.begin(), req.end());
683 string const pkg = lexrc.getString();
685 string const options = lexrc.getString();
686 package_options_[pkg] = options;
690 case TC_DEFAULTMODULE: {
692 string const module = lexrc.getString();
693 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
694 default_modules_.push_back(module);
698 case TC_PROVIDESMODULE: {
700 string const module = lexrc.getString();
701 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
702 provided_modules_.push_back(module);
706 case TC_EXCLUDESMODULE: {
708 string const module = lexrc.getString();
709 // modules already have their own way to exclude other modules
711 LYXERR0("ExcludesModule tag cannot be used in a module!");
714 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
715 excluded_modules_.push_back(module);
719 case TC_LEFTMARGIN: // left margin type
721 leftmargin_ = lexrc.getDocString();
724 case TC_RIGHTMARGIN: // right margin type
726 rightmargin_ = lexrc.getDocString();
729 case TC_INSETLAYOUT: {
731 lexrc.printError("No name given for InsetLayout: `$$Token'.");
735 docstring const name = subst(lexrc.getDocString(), '_', ' ');
737 string s = "Could not read name for InsetLayout: `$$Token' "
738 + lexrc.getString() + " is probably not valid UTF-8!";
741 // Since we couldn't read the name, we just scan the rest
742 // of the style and discard it.
743 il.read(lexrc, *this);
744 // Let's try to continue rather than abort.
746 } else if (hasInsetLayout(name)) {
747 InsetLayout & il = insetlayoutlist_[name];
748 error = !il.read(lexrc, *this);
752 error = !il.read(lexrc, *this);
754 insetlayoutlist_[name] = il;
760 error = !readFloat(lexrc);
764 error = !readCiteEngine(lexrc, rt);
767 case TC_ADDTOCITEENGINE:
768 error = !readCiteEngine(lexrc, rt, true);
771 case TC_CITEENGINETYPE:
773 opt_enginetype_ = rtrim(lexrc.getString());
777 error = !readCiteFormat(lexrc, rt);
780 case TC_CITEFRAMEWORK:
782 citeframework_ = rtrim(lexrc.getString());
785 case TC_MAXCITENAMES:
787 maxcitenames_ = size_t(lexrc.getInteger());
790 case TC_DEFAULTBIBLIO:
792 vector<string> const dbs =
793 getVectorFromString(rtrim(lexrc.getString()), "|");
794 vector<string>::const_iterator it = dbs.begin();
795 vector<string>::const_iterator end = dbs.end();
796 for (; it != end; ++it) {
797 if (!contains(*it, ':')) {
798 vector<string> const enginetypes =
799 getVectorFromString(opt_enginetype_, "|");
800 for (string const &s: enginetypes)
801 cite_default_biblio_style_[s] = *it;
804 string const db = split(*it, eng, ':');
805 cite_default_biblio_style_[eng] = db;
811 case TC_FULLAUTHORLIST:
813 cite_full_author_list_ &= lexrc.getBool();
818 docstring const cnt = lexrc.getDocString();
819 if (!counters_.remove(cnt))
820 LYXERR0("Unable to remove counter: " + to_utf8(cnt));
829 docstring const name = lexrc.getDocString();
831 string s = "Could not read name for counter: `$$Token' "
832 + lexrc.getString() + " is probably not valid UTF-8!";
833 lexrc.printError(s.c_str());
835 // Since we couldn't read the name, we just scan the rest
839 error = !counters_.read(lexrc, name, !ifcounter);
842 lexrc.printError("No name given for style: `$$Token'.");
847 case TC_TITLELATEXTYPE:
848 readTitleType(lexrc);
851 case TC_TITLELATEXNAME:
853 titlename_ = lexrc.getString();
858 string const nofloat = lexrc.getString();
859 floatlist_.erase(nofloat);
863 case TC_OUTLINERNAME:
864 error = !readOutlinerName(lexrc);
869 // at present, we abort if we encounter an error,
870 // so there is no point continuing.
877 if (defaultlayout_.empty()) {
878 LYXERR0("Error: Textclass '" << name_
879 << "' is missing a defaultstyle.");
883 // Try to erase "stdinsets" from the provides_ set.
885 // Provides stdinsets 1
886 // declaration simply tells us that the standard insets have been
887 // defined. (It's found in stdinsets.inc but could also be used in
888 // user-defined files.) There isn't really any such package. So we
889 // might as well go ahead and erase it.
890 // If we do not succeed, then it was not there, which means that
891 // the textclass did not provide the definitions of the standard
892 // insets. So we need to try to load them.
893 int erased = provides_.erase("stdinsets");
895 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
898 frontend::Alert::warning(_("Missing File"),
899 _("Could not find stdinsets.inc! This may lead to data loss!"));
901 } else if (!read(tmp, MERGE)) {
902 frontend::Alert::warning(_("Corrupt File"),
903 _("Could not read stdinsets.inc! This may lead to data loss!"));
908 min_toclevel_ = Layout::NOT_IN_TOC;
909 max_toclevel_ = Layout::NOT_IN_TOC;
910 const_iterator lit = begin();
911 const_iterator len = end();
912 for (; lit != len; ++lit) {
913 int const toclevel = lit->toclevel;
914 if (toclevel != Layout::NOT_IN_TOC) {
915 if (min_toclevel_ == Layout::NOT_IN_TOC)
916 min_toclevel_ = toclevel;
918 min_toclevel_ = min(min_toclevel_, toclevel);
919 max_toclevel_ = max(max_toclevel_, toclevel);
922 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
923 << ", maximum is " << max_toclevel_);
925 return (error ? ERROR : OK);
929 void TextClass::readTitleType(Lexer & lexrc)
931 LexerKeyword titleTypeTags[] = {
932 { "commandafter", TITLE_COMMAND_AFTER },
933 { "environment", TITLE_ENVIRONMENT }
936 PushPopHelper pph(lexrc, titleTypeTags);
938 int le = lexrc.lex();
940 case Lexer::LEX_UNDEF:
941 lexrc.printError("Unknown output type `$$Token'");
943 case TITLE_COMMAND_AFTER:
944 case TITLE_ENVIRONMENT:
945 titletype_ = static_cast<TitleLatexType>(le);
948 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
954 void TextClass::readOutputType(Lexer & lexrc)
956 LexerKeyword outputTypeTags[] = {
957 { "docbook", DOCBOOK },
959 { "literate", LITERATE }
962 PushPopHelper pph(lexrc, outputTypeTags);
964 int le = lexrc.lex();
966 case Lexer::LEX_UNDEF:
967 lexrc.printError("Unknown output type `$$Token'");
972 outputType_ = static_cast<OutputType>(le);
975 LYXERR0("Unhandled value " << le);
981 void TextClass::readClassOptions(Lexer & lexrc)
991 LexerKeyword classOptionsTags[] = {
993 {"fontsize", CO_FONTSIZE },
994 {"header", CO_HEADER },
995 {"other", CO_OTHER },
996 {"pagestyle", CO_PAGESTYLE }
999 lexrc.pushTable(classOptionsTags);
1000 bool getout = false;
1001 while (!getout && lexrc.isOK()) {
1002 int le = lexrc.lex();
1004 case Lexer::LEX_UNDEF:
1005 lexrc.printError("Unknown ClassOption tag `$$Token'");
1013 opt_fontsize_ = rtrim(lexrc.getString());
1017 opt_pagestyle_ = rtrim(lexrc.getString());
1021 if (options_.empty())
1022 options_ = lexrc.getString();
1024 options_ += ',' + lexrc.getString();
1028 class_header_ = subst(lexrc.getString(), """, "\"");
1039 vector<CitationStyle> const & TextClass::getCiteStyles(
1040 CiteEngineType const & type) const
1042 static vector<CitationStyle> empty;
1043 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1044 if (it == cite_styles_.end())
1050 bool TextClass::readCiteEngine(Lexer & lexrc, ReadType rt, bool const add)
1052 int const type = readCiteEngineType(lexrc);
1053 bool authoryear = (type & ENGINE_TYPE_AUTHORYEAR);
1054 bool numerical = (type & ENGINE_TYPE_NUMERICAL);
1055 bool defce = (type & ENGINE_TYPE_DEFAULT);
1057 if (rt == CITE_ENGINE) {
1058 // The cite engines are not supposed to overwrite
1059 // CiteStyle defined by the class or a module.
1061 authoryear = getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1063 numerical = getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1065 defce = getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1068 if (rt != CITE_ENGINE && !add) {
1069 // Reset if we defined CiteStyle
1070 // from the class or a module
1072 cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1074 cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1076 cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1080 bool getout = false;
1081 while (!getout && lexrc.isOK()) {
1083 def = lexrc.getString();
1084 def = subst(def, " ", "");
1085 def = subst(def, "\t", "");
1086 if (compare_ascii_no_case(def, "end") == 0) {
1091 char ichar = def[0];
1094 if (isUpperCase(ichar)) {
1095 cs.forceUpperCase = true;
1096 def[0] = lowercase(ichar);
1099 /** For portability reasons (between different
1100 * cite engines such as natbib and biblatex),
1101 * we distinguish between:
1102 * 1. The LyX name as output in the LyX file
1103 * 2. Possible aliases that might fall back to
1104 * the given LyX name in the current engine
1105 * 3. The actual LaTeX command that is output
1106 * (2) and (3) are optional.
1107 * Also, the GUI string for the starred version can
1110 * LyXName|alias,nextalias*<!stardesc!stardesctooltip>[][]=latexcmd
1119 ScanMode mode = LyXName;
1120 ScanMode oldmode = LyXName;
1125 size_t const n = def.size();
1126 for (size_t i = 0; i != n; ++i) {
1130 else if (ichar == '=')
1132 else if (ichar == '<') {
1135 } else if (ichar == '>')
1137 else if (mode == LaTeXCmd)
1139 else if (mode == StarDesc)
1141 else if (ichar == '$')
1142 cs.hasQualifiedList = true;
1143 else if (ichar == '*')
1144 cs.hasStarredVersion = true;
1145 else if (ichar == '[' && cs.textAfter)
1146 cs.textBefore = true;
1147 else if (ichar == '[')
1148 cs.textAfter = true;
1149 else if (ichar != ']') {
1157 cs.cmd = latex_cmd.empty() ? lyx_cmd : latex_cmd;
1158 if (!alias.empty()) {
1159 vector<string> const aliases = getVectorFromString(alias);
1160 for (string const &s: aliases)
1161 cite_command_aliases_[s] = lyx_cmd;
1163 vector<string> const stardescs = getVectorFromString(stardesc, "!");
1164 int size = stardesc.size();
1166 cs.stardesc = stardescs[0];
1168 cs.startooltip = stardescs[1];
1171 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1173 class_cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1175 class_cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1178 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1180 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1182 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1185 // If we do AddToCiteEngine, do not apply yet,
1186 // except if we have already a style to add something to
1187 bool apply_ay = !add;
1188 bool apply_num = !add;
1189 bool apply_def = !add;
1191 if (type & ENGINE_TYPE_AUTHORYEAR)
1192 apply_ay = !getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1193 if (type & ENGINE_TYPE_NUMERICAL)
1194 apply_num = !getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1195 if (type & ENGINE_TYPE_DEFAULT)
1196 apply_def = !getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1199 // Add the styles from AddToCiteEngine to the class' styles
1200 // (but only if they are not yet defined)
1201 for (auto const cis : class_cite_styles_) {
1202 // Only consider the current CiteEngineType
1203 if (!(type & cis.first))
1205 for (auto const ciss : cis.second) {
1206 bool defined = false;
1207 // Check if the style "name" is already def'ed
1208 for (auto const av : getCiteStyles(cis.first))
1209 if (av.name == ciss.name)
1212 if (cis.first == ENGINE_TYPE_AUTHORYEAR && apply_ay)
1213 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(ciss);
1214 else if (cis.first == ENGINE_TYPE_NUMERICAL && apply_num)
1215 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(ciss);
1216 else if (cis.first == ENGINE_TYPE_DEFAULT && apply_def)
1217 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(ciss);
1221 if (type & ENGINE_TYPE_AUTHORYEAR && apply_ay)
1222 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1223 if (type & ENGINE_TYPE_NUMERICAL && apply_num)
1224 class_cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1225 if (type & ENGINE_TYPE_DEFAULT && apply_def)
1226 class_cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1231 int TextClass::readCiteEngineType(Lexer & lexrc) const
1233 static_assert(ENGINE_TYPE_DEFAULT ==
1234 (ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL),
1235 "Incorrect default engine type");
1236 if (!lexrc.next()) {
1237 lexrc.printError("No cite engine type given for token: `$$Token'.");
1238 return ENGINE_TYPE_DEFAULT;
1240 string const type = rtrim(lexrc.getString());
1241 if (compare_ascii_no_case(type, "authoryear") == 0)
1242 return ENGINE_TYPE_AUTHORYEAR;
1243 else if (compare_ascii_no_case(type, "numerical") == 0)
1244 return ENGINE_TYPE_NUMERICAL;
1245 else if (compare_ascii_no_case(type, "default") != 0) {
1246 string const s = "Unknown cite engine type `" + type
1247 + "' given for token: `$$Token',";
1248 lexrc.printError(s);
1250 return ENGINE_TYPE_DEFAULT;
1254 bool TextClass::readCiteFormat(Lexer & lexrc, ReadType rt)
1256 int const type = readCiteEngineType(lexrc);
1259 // Cite engine definitions do not overwrite existing
1260 // definitions from the class or a module
1261 bool const overwrite = rt != CITE_ENGINE;
1262 while (lexrc.isOK()) {
1264 etype = lexrc.getString();
1265 if (compare_ascii_no_case(etype, "end") == 0)
1270 definition = lexrc.getString();
1271 char initchar = etype[0];
1272 if (initchar == '#')
1274 if (initchar == '!' || initchar == '_' || prefixIs(etype, "B_")) {
1275 bool defined = false;
1276 // Check if the macro is already def'ed
1277 for (auto const cm : cite_macros_) {
1278 if (!(type & cm.first))
1280 if (cm.second.find(etype) != cm.second.end())
1283 if (!defined || overwrite) {
1284 if (type & ENGINE_TYPE_AUTHORYEAR)
1285 cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1286 if (type & ENGINE_TYPE_NUMERICAL)
1287 cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1288 if (type & ENGINE_TYPE_DEFAULT)
1289 cite_macros_[ENGINE_TYPE_DEFAULT][etype] = definition;
1292 bool defined = false;
1293 // Check if the format is already def'ed
1294 for (auto const cm : cite_formats_) {
1295 if (!(type & cm.first))
1297 if (cm.second.find(etype) != cm.second.end())
1300 if (!defined || overwrite){
1301 if (type & ENGINE_TYPE_AUTHORYEAR)
1302 cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1303 if (type & ENGINE_TYPE_NUMERICAL)
1304 cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1305 if (type & ENGINE_TYPE_DEFAULT)
1306 cite_formats_[ENGINE_TYPE_DEFAULT][etype] = definition;
1314 bool TextClass::readFloat(Lexer & lexrc)
1331 FT_ALLOWED_PLACEMENT,
1337 LexerKeyword floatTags[] = {
1338 { "allowedplacement", FT_ALLOWED_PLACEMENT },
1339 { "allowssideways", FT_ALLOWS_SIDEWAYS },
1340 { "allowswide", FT_ALLOWS_WIDE },
1342 { "extension", FT_EXT },
1343 { "guiname", FT_NAME },
1344 { "htmlattr", FT_HTMLATTR },
1345 { "htmlstyle", FT_HTMLSTYLE },
1346 { "htmltag", FT_HTMLTAG },
1347 { "ispredefined", FT_PREDEFINED },
1348 { "listcommand", FT_LISTCOMMAND },
1349 { "listname", FT_LISTNAME },
1350 { "numberwithin", FT_WITHIN },
1351 { "placement", FT_PLACEMENT },
1352 { "refprefix", FT_REFPREFIX },
1353 { "style", FT_STYLE },
1354 { "type", FT_TYPE },
1355 { "usesfloatpkg", FT_USESFLOAT }
1358 lexrc.pushTable(floatTags);
1362 docstring htmlstyle;
1368 string allowed_placement = "!htbpH";
1373 bool usesfloat = true;
1374 bool ispredefined = false;
1375 bool allowswide = true;
1376 bool allowssideways = true;
1378 bool getout = false;
1379 while (!getout && lexrc.isOK()) {
1380 int le = lexrc.lex();
1382 case Lexer::LEX_UNDEF:
1383 lexrc.printError("Unknown float tag `$$Token'");
1391 type = lexrc.getString();
1392 if (floatlist_.typeExist(type)) {
1393 Floating const & fl = floatlist_.getType(type);
1394 placement = fl.placement();
1396 within = fl.within();
1399 listname = fl.listName();
1400 usesfloat = fl.usesFloatPkg();
1401 ispredefined = fl.isPredefined();
1402 listcommand = fl.listCommand();
1403 refprefix = fl.refPrefix();
1408 name = lexrc.getString();
1412 placement = lexrc.getString();
1414 case FT_ALLOWED_PLACEMENT:
1416 allowed_placement = lexrc.getString();
1420 ext = lexrc.getString();
1424 within = lexrc.getString();
1425 if (within == "none")
1430 style = lexrc.getString();
1432 case FT_LISTCOMMAND:
1434 listcommand = lexrc.getString();
1438 refprefix = lexrc.getString();
1442 listname = lexrc.getString();
1446 usesfloat = lexrc.getBool();
1450 ispredefined = lexrc.getBool();
1452 case FT_ALLOWS_SIDEWAYS:
1454 allowssideways = lexrc.getBool();
1456 case FT_ALLOWS_WIDE:
1458 allowswide = lexrc.getBool();
1462 htmlattr = lexrc.getString();
1466 htmlstyle = lexrc.getLongString(from_ascii("EndHTMLStyle"));
1470 htmltag = lexrc.getString();
1480 // Here we have a full float if getout == true
1482 if (!usesfloat && listcommand.empty()) {
1483 // if this float uses the same auxfile as an existing one,
1484 // there is no need for it to provide a list command.
1485 FloatList::const_iterator it = floatlist_.begin();
1486 FloatList::const_iterator en = floatlist_.end();
1487 bool found_ext = false;
1488 for (; it != en; ++it) {
1489 if (it->second.ext() == ext) {
1495 LYXERR0("The layout does not provide a list command " <<
1496 "for the float `" << type << "'. LyX will " <<
1497 "not be able to produce a float list.");
1499 Floating fl(type, placement, ext, within, style, name,
1500 listname, listcommand, refprefix, allowed_placement,
1501 htmltag, htmlattr, htmlstyle, usesfloat, ispredefined,
1502 allowswide, allowssideways);
1503 floatlist_.newFloat(fl);
1504 // each float has its own counter
1505 counters_.newCounter(from_ascii(type), from_ascii(within),
1506 docstring(), docstring());
1507 // also define sub-float counters
1508 docstring const subtype = "sub-" + from_ascii(type);
1509 counters_.newCounter(subtype, from_ascii(type),
1510 "\\alph{" + subtype + "}", docstring());
1516 bool TextClass::readOutlinerName(Lexer & lexrc)
1521 type = lexrc.getString();
1523 lexrc.printError("No type given for OutlinerName: `$$Token'.");
1527 name = lexrc.getDocString();
1529 lexrc.printError("No name given for OutlinerName: `$$Token'.");
1532 outliner_names_[type] = name;
1537 string const & TextClass::prerequisites(string const & sep) const
1539 if (contains(prerequisites_, ',')) {
1540 vector<string> const pres = getVectorFromString(prerequisites_);
1541 prerequisites_ = getStringFromVector(pres, sep);
1543 return prerequisites_;
1547 bool TextClass::hasLayout(docstring const & n) const
1549 docstring const name = n.empty() ? defaultLayoutName() : n;
1551 return find_if(layoutlist_.begin(), layoutlist_.end(),
1552 LayoutNamesEqual(name))
1553 != layoutlist_.end();
1557 bool TextClass::hasInsetLayout(docstring const & n) const
1561 InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
1562 return it != insetlayoutlist_.end();
1566 Layout const & TextClass::operator[](docstring const & name) const
1568 LATTEST(!name.empty());
1571 find_if(begin(), end(), LayoutNamesEqual(name));
1574 LYXERR0("We failed to find the layout '" << name
1575 << "' in the layout list. You MUST investigate!");
1576 for (const_iterator cit = begin(); cit != end(); ++cit)
1577 lyxerr << " " << to_utf8(cit->name()) << endl;
1579 // We require the name to exist
1580 static const Layout dummy;
1581 LASSERT(false, return dummy);
1588 Layout & TextClass::operator[](docstring const & name)
1590 LATTEST(!name.empty());
1591 // Safe to continue, given what we do below.
1593 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1596 LYXERR0("We failed to find the layout '" << to_utf8(name)
1597 << "' in the layout list. You MUST investigate!");
1598 for (const_iterator cit = begin(); cit != end(); ++cit)
1599 LYXERR0(" " << to_utf8(cit->name()));
1601 // we require the name to exist
1603 // we are here only in release mode
1604 layoutlist_.push_back(createBasicLayout(name, true));
1605 it = find_if(begin(), end(), LayoutNamesEqual(name));
1612 bool TextClass::deleteLayout(docstring const & name)
1614 if (name == defaultLayoutName() || name == plainLayoutName())
1617 LayoutList::iterator it =
1618 remove_if(layoutlist_.begin(), layoutlist_.end(),
1619 LayoutNamesEqual(name));
1621 LayoutList::iterator end = layoutlist_.end();
1622 bool const ret = (it != end);
1623 layoutlist_.erase(it, end);
1628 bool TextClass::deleteInsetLayout(docstring const & name)
1630 return insetlayoutlist_.erase(name);
1634 // Load textclass info if not loaded yet
1635 bool TextClass::load(string const & path) const
1640 // Read style-file, provided path is searched before the system ones
1641 // If path is a file, it is loaded directly.
1642 FileName layout_file(path);
1643 if (!path.empty() && !layout_file.isReadableFile())
1644 layout_file = FileName(addName(path, name_ + ".layout"));
1645 if (layout_file.empty() || !layout_file.exists())
1646 layout_file = libFileSearch("layouts", name_, "layout");
1647 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1650 lyxerr << "Error reading `"
1651 << to_utf8(makeDisplayPath(layout_file.absFileName()))
1652 << "'\n(Check `" << name_
1653 << "')\nCheck your installation and "
1654 "try Options/Reconfigure..."
1662 bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
1667 layoutlist_.push_back(createBasicLayout(n, true));
1672 string DocumentClass::forcedLayouts() const
1676 const_iterator const e = end();
1677 for (const_iterator i = begin(); i != e; ++i) {
1678 if (i->forcelocal > 0) {
1680 os << "Format " << LAYOUT_FORMAT << '\n';
1690 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1692 // FIXME The fix for the InsetLayout part of 4812 would be here:
1693 // Add the InsetLayout to the document class if it is not found.
1695 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1696 while (!n.empty()) {
1697 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1698 if (cit != cen && cit->first == n) {
1699 if (cit->second.obsoleted_by().empty())
1701 n = cit->second.obsoleted_by();
1702 return insetLayout(n);
1704 // If we have a generic prefix (e.g., "Note:"),
1705 // try if this one alone is found.
1706 size_t i = n.find(':');
1707 if (i == string::npos)
1711 // Layout "name" not found.
1712 return plainInsetLayout();
1716 InsetLayout const & DocumentClass::plainInsetLayout() {
1717 static const InsetLayout plain_insetlayout_;
1718 return plain_insetlayout_;
1722 docstring const & TextClass::defaultLayoutName() const
1724 return defaultlayout_;
1728 Layout const & TextClass::defaultLayout() const
1730 return operator[](defaultLayoutName());
1734 bool TextClass::isDefaultLayout(Layout const & layout) const
1736 return layout.name() == defaultLayoutName();
1740 bool TextClass::isPlainLayout(Layout const & layout) const
1742 return layout.name() == plainLayoutName();
1746 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1748 static Layout * defaultLayout = NULL;
1750 if (defaultLayout) {
1751 defaultLayout->setUnknown(unknown);
1752 defaultLayout->setName(name);
1753 return *defaultLayout;
1756 static char const * s = "Margin Static\n"
1757 "LatexType Paragraph\n"
1760 "AlignPossible Left, Right, Center\n"
1761 "LabelType No_Label\n"
1763 istringstream ss(s);
1764 Lexer lex(textClassTags);
1766 defaultLayout = new Layout;
1767 defaultLayout->setUnknown(unknown);
1768 defaultLayout->setName(name);
1769 if (!readStyle(lex, *defaultLayout)) {
1770 // The only way this happens is because the hardcoded layout above
1774 return *defaultLayout;
1778 DocumentClassPtr getDocumentClass(
1779 LayoutFile const & baseClass, LayoutModuleList const & modlist,
1780 string const & cengine, bool const clone)
1782 DocumentClassPtr doc_class =
1783 DocumentClassPtr(new DocumentClass(baseClass));
1784 LayoutModuleList::const_iterator it = modlist.begin();
1785 LayoutModuleList::const_iterator en = modlist.end();
1786 for (; it != en; ++it) {
1787 string const modName = *it;
1788 LyXModule * lm = theModuleList[modName];
1790 docstring const msg =
1791 bformat(_("The module %1$s has been requested by\n"
1792 "this document but has not been found in the list of\n"
1793 "available modules. If you recently installed it, you\n"
1794 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1796 frontend::Alert::warning(_("Module not available"), msg);
1799 if (!lm->isAvailable() && !clone) {
1800 docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
1801 docstring const msg =
1802 bformat(_("The module %1$s requires a package that is not\n"
1803 "available in your LaTeX installation, or a converter that\n"
1804 "you have not installed. LaTeX output may not be possible.\n"
1805 "Missing prerequisites:\n"
1807 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1808 from_utf8(modName), prereqs);
1809 frontend::Alert::warning(_("Package not available"), msg, true);
1811 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1812 if (!doc_class->read(layout_file, TextClass::MODULE)) {
1813 docstring const msg =
1814 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1815 frontend::Alert::warning(_("Read Error"), msg);
1819 if (cengine.empty())
1822 LyXCiteEngine * ce = theCiteEnginesList[cengine];
1824 docstring const msg =
1825 bformat(_("The cite engine %1$s has been requested by\n"
1826 "this document but has not been found in the list of\n"
1827 "available engines. If you recently installed it, you\n"
1828 "probably need to reconfigure LyX.\n"), from_utf8(cengine));
1830 frontend::Alert::warning(_("Cite Engine not available"), msg);
1831 } else if (!ce->isAvailable() && !clone) {
1832 docstring const prereqs = from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
1833 docstring const msg =
1834 bformat(_("The cite engine %1$s requires a package that is not\n"
1835 "available in your LaTeX installation, or a converter that\n"
1836 "you have not installed. LaTeX output may not be possible.\n"
1837 "Missing prerequisites:\n"
1839 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1840 from_utf8(cengine), prereqs);
1841 frontend::Alert::warning(_("Package not available"), msg, true);
1843 FileName layout_file = libFileSearch("citeengines", ce->getFilename());
1844 if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
1845 docstring const msg =
1846 bformat(_("Error reading cite engine %1$s\n"), from_utf8(cengine));
1847 frontend::Alert::warning(_("Read Error"), msg);
1855 /////////////////////////////////////////////////////////////////////////
1859 /////////////////////////////////////////////////////////////////////////
1861 DocumentClass::DocumentClass(LayoutFile const & tc)
1866 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1868 LayoutList::const_iterator it = layoutlist_.begin();
1869 LayoutList::const_iterator end = layoutlist_.end();
1870 for (; it != end; ++it)
1871 if (it->latexname() == lay)
1877 bool DocumentClass::provides(string const & p) const
1879 return provides_.find(p) != provides_.end();
1883 bool DocumentClass::hasTocLevels() const
1885 return min_toclevel_ != Layout::NOT_IN_TOC;
1889 Layout const & DocumentClass::getTOCLayout() const
1891 // we're going to look for the layout with the minimum toclevel
1892 TextClass::LayoutList::const_iterator lit = begin();
1893 TextClass::LayoutList::const_iterator const len = end();
1894 int minlevel = 1000;
1895 Layout const * lay = NULL;
1896 for (; lit != len; ++lit) {
1897 int const level = lit->toclevel;
1898 // we don't want Part or unnumbered sections
1899 if (level == Layout::NOT_IN_TOC || level < 0
1900 || level >= minlevel || lit->counter.empty())
1907 // hmm. that is very odd, so we'll do our best.
1908 return operator[](defaultLayoutName());
1912 Layout const & DocumentClass::htmlTOCLayout() const
1914 if (html_toc_section_.empty())
1915 html_toc_section_ = getTOCLayout().name();
1916 return operator[](html_toc_section_);
1920 string const DocumentClass::getCiteFormat(CiteEngineType const & type,
1921 string const & entry, bool const punct, string const & fallback) const
1923 string default_format = "{%fullnames:author%[[%fullnames:author%, ]][[{%fullnames:editor%[[%fullnames:editor%, ed., ]]}]]}\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]][[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}";
1925 default_format += ".";
1927 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
1928 if (itype == cite_formats_.end())
1929 return default_format;
1930 map<string, string>::const_iterator it = itype->second.find(entry);
1931 if (it == itype->second.end() && !fallback.empty())
1932 it = itype->second.find(fallback);
1933 if (it == itype->second.end())
1934 return default_format;
1936 return it->second + ".";
1941 string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
1942 string const & macro) const
1944 static string empty;
1945 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
1946 if (itype == cite_macros_.end())
1948 map<string, string>::const_iterator it = itype->second.find(macro);
1949 if (it == itype->second.end())
1955 vector<string> const DocumentClass::citeCommands(
1956 CiteEngineType const & type) const
1958 vector<CitationStyle> const styles = citeStyles(type);
1959 vector<CitationStyle>::const_iterator it = styles.begin();
1960 vector<CitationStyle>::const_iterator end = styles.end();
1961 vector<string> cmds;
1962 for (; it != end; ++it) {
1963 CitationStyle const cite = *it;
1964 cmds.push_back(cite.name);
1970 vector<CitationStyle> const & DocumentClass::citeStyles(
1971 CiteEngineType const & type) const
1973 static vector<CitationStyle> empty;
1974 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1975 if (it == cite_styles_.end())
1981 /////////////////////////////////////////////////////////////////////////
1985 /////////////////////////////////////////////////////////////////////////
1987 ostream & operator<<(ostream & os, PageSides p)