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 = 80; // spitz: Requires for floats
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_pagesize_("default|a4|a5|b5|letter|legal|executive"),
154 opt_pagestyle_("empty|plain|headings|fancy"), fontsize_format_("$$spt"), pagesize_("default"),
155 pagesize_format_("$$spaper"), pagestyle_("default"), tablestyle_("default"),
156 columns_(1), sides_(OneSide), secnumdepth_(3), tocdepth_(3), outputType_(LATEX),
157 outputFormat_("latex"), has_output_format_(false), defaultfont_(sane_font),
158 titletype_(TITLE_COMMAND_AFTER), titlename_("maketitle"),
159 min_toclevel_(0), max_toclevel_(0), maxcitenames_(2),
160 cite_full_author_list_(true), bibintoc_(false)
165 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
167 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
168 if (!lay.read(lexrc, *this)) {
169 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
173 lay.resfont = lay.font;
174 lay.resfont.realize(defaultfont_);
175 lay.reslabelfont = lay.labelfont;
176 lay.reslabelfont.realize(defaultfont_);
177 return true; // no errors
217 TC_ADDTOHTMLPREAMBLE,
239 LexerKeyword textClassTags[] = {
240 { "addtociteengine", TC_ADDTOCITEENGINE },
241 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
242 { "addtohtmlstyles", TC_ADDTOHTMLSTYLES },
243 { "addtopreamble", TC_ADDTOPREAMBLE },
244 { "bibintoc", TC_BIBINTOC },
245 { "citeengine", TC_CITEENGINE },
246 { "citeenginetype", TC_CITEENGINETYPE },
247 { "citeformat", TC_CITEFORMAT },
248 { "citeframework", TC_CITEFRAMEWORK },
249 { "classoptions", TC_CLASSOPTIONS },
250 { "columns", TC_COLUMNS },
251 { "counter", TC_COUNTER },
252 { "defaultbiblio", TC_DEFAULTBIBLIO },
253 { "defaultfont", TC_DEFAULTFONT },
254 { "defaultmodule", TC_DEFAULTMODULE },
255 { "defaultstyle", TC_DEFAULTSTYLE },
256 { "excludesmodule", TC_EXCLUDESMODULE },
257 { "float", TC_FLOAT },
258 { "format", TC_FORMAT },
259 { "fullauthorlist", TC_FULLAUTHORLIST },
260 { "htmlpreamble", TC_HTMLPREAMBLE },
261 { "htmlstyles", TC_HTMLSTYLES },
262 { "htmltocsection", TC_HTMLTOCSECTION },
263 { "ifcounter", TC_IFCOUNTER },
264 { "input", TC_INPUT },
265 { "insetlayout", TC_INSETLAYOUT },
266 { "leftmargin", TC_LEFTMARGIN },
267 { "maxcitenames", TC_MAXCITENAMES },
268 { "modifystyle", TC_MODIFYSTYLE },
269 { "nocounter", TC_NOCOUNTER },
270 { "nofloat", TC_NOFLOAT },
271 { "noinsetlayout", TC_NOINSETLAYOUT },
272 { "nostyle", TC_NOSTYLE },
273 { "outlinername", TC_OUTLINERNAME },
274 { "outputformat", TC_OUTPUTFORMAT },
275 { "outputtype", TC_OUTPUTTYPE },
276 { "packageoptions", TC_PKGOPTS },
277 { "pagesize", TC_PAGESIZE },
278 { "pagestyle", TC_PAGESTYLE },
279 { "preamble", TC_PREAMBLE },
280 { "provides", TC_PROVIDES },
281 { "providesmodule", TC_PROVIDESMODULE },
282 { "providestyle", TC_PROVIDESTYLE },
283 { "requires", TC_REQUIRES },
284 { "rightmargin", TC_RIGHTMARGIN },
285 { "secnumdepth", TC_SECNUMDEPTH },
286 { "sides", TC_SIDES },
287 { "style", TC_STYLE },
288 { "tablestyle", TC_TABLESTYLE },
289 { "titlelatexname", TC_TITLELATEXNAME },
290 { "titlelatextype", TC_TITLELATEXTYPE },
291 { "tocdepth", TC_TOCDEPTH }
297 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
299 LYXERR(Debug::TCLASS, "Converting layout file to " << LAYOUT_FORMAT);
300 TempFile tmp("convertXXXXXX.layout");
301 FileName const tempfile = tmp.name();
302 bool success = layout2layout(filename, tempfile);
304 success = readWithoutConv(tempfile, rt) == OK;
309 std::string TextClass::convert(std::string const & str)
311 TempFile tmp1("localXXXXXX.layout");
312 FileName const fn = tmp1.name();
313 ofstream os(fn.toFilesystemEncoding().c_str());
316 TempFile tmp2("convert_localXXXXXX.layout");
317 FileName const tempfile = tmp2.name();
318 bool success = layout2layout(fn, tempfile, LYXFILE_LAYOUT_FORMAT);
321 ifstream is(tempfile.toFilesystemEncoding().c_str());
333 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
335 if (!filename.isReadableFile()) {
336 lyxerr << "Cannot read layout file `" << filename << "'."
341 LYXERR(Debug::TCLASS, "Reading " + translateReadType(rt) + ": " +
342 to_utf8(makeDisplayPath(filename.absFileName())));
344 // Define the plain layout used in table cells, ert, etc. Note that
345 // we do this before loading any layout file, so that classes can
346 // override features of this layout if they should choose to do so.
347 if (rt == BASECLASS && !hasLayout(plain_layout_))
348 layoutlist_.push_back(createBasicLayout(plain_layout_));
350 Lexer lexrc(textClassTags);
351 lexrc.setFile(filename);
352 ReturnValues retval = read(lexrc, rt);
354 LYXERR(Debug::TCLASS, "Finished reading " + translateReadType(rt) + ": " +
355 to_utf8(makeDisplayPath(filename.absFileName())));
361 bool TextClass::read(FileName const & filename, ReadType rt)
363 ReturnValues const retval = readWithoutConv(filename, rt);
364 if (retval != FORMAT_MISMATCH)
367 bool const worx = convertLayoutFormat(filename, rt);
369 LYXERR0 ("Unable to convert " << filename <<
370 " to format " << LAYOUT_FORMAT);
375 TextClass::ReturnValues TextClass::validate(std::string const & str)
378 return tc.read(str, VALIDATION);
382 TextClass::ReturnValues TextClass::read(std::string const & str, ReadType rt)
384 Lexer lexrc(textClassTags);
385 istringstream is(str);
387 ReturnValues retval = read(lexrc, rt);
389 if (retval != FORMAT_MISMATCH)
392 // write the layout string to a temporary file
393 TempFile tmp("TextClass_read");
394 FileName const tempfile = tmp.name();
395 ofstream os(tempfile.toFilesystemEncoding().c_str());
397 LYXERR0("Unable to create temporary file");
403 // now try to convert it to LAYOUT_FORMAT
404 if (!convertLayoutFormat(tempfile, rt)) {
405 LYXERR0("Unable to convert internal layout information to format "
414 // Reads a textclass structure from file.
415 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
420 // The first usable line should be
421 // Format LAYOUT_FORMAT
422 if (lexrc.lex() != TC_FORMAT || !lexrc.next()
423 || lexrc.getInteger() != LAYOUT_FORMAT)
424 return FORMAT_MISMATCH;
428 while (lexrc.isOK() && !error) {
429 int le = lexrc.lex();
432 case Lexer::LEX_FEOF:
435 case Lexer::LEX_UNDEF:
436 lexrc.printError("Unknown TextClass tag `$$Token'");
444 // used below to track whether we are in an IfStyle or IfCounter tag.
445 bool modifystyle = false;
446 bool providestyle = false;
447 bool ifcounter = false;
449 switch (static_cast<TextClassTags>(le)) {
453 lexrc.printError("Duplicate Format directive");
456 case TC_OUTPUTFORMAT:
458 outputFormat_ = lexrc.getString();
459 has_output_format_ = true;
464 readOutputType(lexrc);
465 switch(outputType_) {
467 outputFormat_ = "latex";
470 outputFormat_ = "docbook";
473 outputFormat_ = "literate";
478 case TC_INPUT: // Include file
481 string const inc = lexrc.getString();
482 if (!path().empty() && (prefixIs(inc, "./") ||
483 prefixIs(inc, "../")))
484 tmp = fileSearch(path(), inc, "layout");
486 tmp = libFileSearch("layouts", inc,
490 lexrc.printError("Could not find input file: " + inc);
492 } else if (!read(tmp, MERGE)) {
493 lexrc.printError("Error reading input file: " + tmp.absFileName());
499 case TC_DEFAULTSTYLE:
501 docstring const name = from_utf8(subst(lexrc.getString(),
503 defaultlayout_ = name;
510 case TC_PROVIDESTYLE:
511 // if modifystyle is true, then we got here by falling through
512 // so we are not in an ProvideStyle block
518 lexrc.printError("No name given for style: `$$Token'.");
522 docstring const name = from_utf8(subst(lexrc.getString(),
525 string s = "Could not read name for style: `$$Token' "
526 + lexrc.getString() + " is probably not valid UTF-8!";
529 // Since we couldn't read the name, we just scan the rest
530 // of the style and discard it.
531 error = !readStyle(lexrc, lay);
535 bool const have_layout = hasLayout(name);
537 // If the layout already exists, then we want to add it to
538 // the existing layout, as long as we are not in an ProvideStyle
540 if (have_layout && !providestyle) {
541 Layout & lay = operator[](name);
542 error = !readStyle(lexrc, lay);
544 // If the layout does not exist, then we want to create a new
545 // one, but not if we are in a ModifyStyle block.
546 else if (!have_layout && !modifystyle) {
548 layout.setName(name);
549 error = !readStyle(lexrc, layout);
551 layoutlist_.push_back(layout);
553 if (defaultlayout_.empty()) {
554 // We do not have a default layout yet, so we choose
555 // the first layout we encounter.
556 defaultlayout_ = name;
559 // There are two ways to get here:
560 // (i) The layout exists but we are in an ProvideStyle block
561 // (ii) The layout doesn't exist, but we are in an ModifyStyle
563 // Either way, we just scan the rest and discard it
566 // signal to coverity that we do not care about the result
567 (void)readStyle(lexrc, lay);
574 docstring const style = from_utf8(subst(lexrc.getString(),
576 if (!deleteLayout(style))
577 lyxerr << "Cannot delete style `"
578 << to_utf8(style) << '\'' << endl;
582 case TC_NOINSETLAYOUT:
584 docstring const style = from_utf8(subst(lexrc.getString(),
586 if (!deleteInsetLayout(style))
587 LYXERR0("Style `" << style << "' cannot be removed\n"
588 "because it was not found!");
594 columns_ = lexrc.getInteger();
599 switch (lexrc.getInteger()) {
600 case 1: sides_ = OneSide; break;
601 case 2: sides_ = TwoSides; break;
603 lyxerr << "Impossible number of page"
604 " sides, setting to one."
614 pagesize_ = rtrim(lexrc.getString());
619 pagestyle_ = rtrim(lexrc.getString());
623 defaultfont_ = lyxRead(lexrc);
624 if (!defaultfont_.resolved()) {
625 lexrc.printError("Warning: defaultfont should "
626 "be fully instantiated!");
627 defaultfont_.realize(sane_font);
633 secnumdepth_ = lexrc.getInteger();
638 tocdepth_ = lexrc.getInteger();
641 // First step to support options
642 case TC_CLASSOPTIONS:
643 readClassOptions(lexrc);
647 preamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
650 case TC_HTMLPREAMBLE:
651 htmlpreamble_ = lexrc.getLongString(from_ascii("EndPreamble"));
655 htmlstyles_ = lexrc.getLongString(from_ascii("EndStyles"));
658 case TC_HTMLTOCSECTION:
659 html_toc_section_ = from_utf8(trim(lexrc.getString()));
662 case TC_ADDTOPREAMBLE:
663 preamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
666 case TC_ADDTOHTMLPREAMBLE:
667 htmlpreamble_ += lexrc.getLongString(from_ascii("EndPreamble"));
670 case TC_ADDTOHTMLSTYLES:
671 htmlstyles_ += lexrc.getLongString(from_ascii("EndStyles"));
676 string const feature = lexrc.getString();
678 if (lexrc.getInteger())
679 provides_.insert(feature);
681 provides_.erase(feature);
687 vector<string> const req
688 = getVectorFromString(lexrc.getString());
689 requires_.insert(req.begin(), req.end());
695 string const pkg = lexrc.getString();
697 string const options = lexrc.getString();
698 package_options_[pkg] = options;
702 case TC_DEFAULTMODULE: {
704 string const module = lexrc.getString();
705 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
706 default_modules_.push_back(module);
710 case TC_PROVIDESMODULE: {
712 string const module = lexrc.getString();
713 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
714 provided_modules_.push_back(module);
718 case TC_EXCLUDESMODULE: {
720 string const module = lexrc.getString();
721 // modules already have their own way to exclude other modules
723 LYXERR0("ExcludesModule tag cannot be used in a module!");
726 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
727 excluded_modules_.push_back(module);
731 case TC_LEFTMARGIN: // left margin type
733 leftmargin_ = lexrc.getDocString();
736 case TC_RIGHTMARGIN: // right margin type
738 rightmargin_ = lexrc.getDocString();
741 case TC_INSETLAYOUT: {
743 lexrc.printError("No name given for InsetLayout: `$$Token'.");
747 docstring const name = subst(lexrc.getDocString(), '_', ' ');
749 string s = "Could not read name for InsetLayout: `$$Token' "
750 + lexrc.getString() + " is probably not valid UTF-8!";
753 // Since we couldn't read the name, we just scan the rest
754 // of the style and discard it.
755 il.read(lexrc, *this);
756 // Let's try to continue rather than abort.
758 } else if (hasInsetLayout(name)) {
759 InsetLayout & il = insetlayoutlist_[name];
760 error = !il.read(lexrc, *this);
764 error = !il.read(lexrc, *this);
766 insetlayoutlist_[name] = il;
772 error = !readFloat(lexrc);
776 error = !readCiteEngine(lexrc, rt);
779 case TC_ADDTOCITEENGINE:
780 error = !readCiteEngine(lexrc, rt, true);
783 case TC_CITEENGINETYPE:
785 opt_enginetype_ = rtrim(lexrc.getString());
789 error = !readCiteFormat(lexrc, rt);
792 case TC_CITEFRAMEWORK:
794 citeframework_ = rtrim(lexrc.getString());
797 case TC_MAXCITENAMES:
799 maxcitenames_ = size_t(lexrc.getInteger());
802 case TC_DEFAULTBIBLIO:
804 vector<string> const dbs =
805 getVectorFromString(rtrim(lexrc.getString()), "|");
806 vector<string>::const_iterator it = dbs.begin();
807 vector<string>::const_iterator end = dbs.end();
808 for (; it != end; ++it) {
809 if (!contains(*it, ':')) {
810 vector<string> const enginetypes =
811 getVectorFromString(opt_enginetype_, "|");
812 for (string const &s: enginetypes)
813 cite_default_biblio_style_[s] = *it;
816 string const db = split(*it, eng, ':');
817 cite_default_biblio_style_[eng] = db;
825 bibintoc_ = lexrc.getBool();
828 case TC_FULLAUTHORLIST:
830 cite_full_author_list_ &= lexrc.getBool();
835 docstring const cnt = lexrc.getDocString();
836 if (!counters_.remove(cnt))
837 LYXERR0("Unable to remove counter: " + to_utf8(cnt));
846 docstring const name = lexrc.getDocString();
848 string s = "Could not read name for counter: `$$Token' "
849 + lexrc.getString() + " is probably not valid UTF-8!";
850 lexrc.printError(s.c_str());
852 // Since we couldn't read the name, we just scan the rest
856 error = !counters_.read(lexrc, name, !ifcounter);
859 lexrc.printError("No name given for style: `$$Token'.");
864 case TC_TITLELATEXTYPE:
865 readTitleType(lexrc);
868 case TC_TITLELATEXNAME:
870 titlename_ = lexrc.getString();
875 string const nofloat = lexrc.getString();
876 floatlist_.erase(nofloat);
880 case TC_OUTLINERNAME:
881 error = !readOutlinerName(lexrc);
886 tablestyle_ = rtrim(lexrc.getString());
891 // at present, we abort if we encounter an error,
892 // so there is no point continuing.
899 if (defaultlayout_.empty()) {
900 LYXERR0("Error: Textclass '" << name_
901 << "' is missing a defaultstyle.");
905 // Try to erase "stdinsets" from the provides_ set.
907 // Provides stdinsets 1
908 // declaration simply tells us that the standard insets have been
909 // defined. (It's found in stdinsets.inc but could also be used in
910 // user-defined files.) There isn't really any such package. So we
911 // might as well go ahead and erase it.
912 // If we do not succeed, then it was not there, which means that
913 // the textclass did not provide the definitions of the standard
914 // insets. So we need to try to load them.
915 int erased = provides_.erase("stdinsets");
917 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
920 frontend::Alert::warning(_("Missing File"),
921 _("Could not find stdinsets.inc! This may lead to data loss!"));
923 } else if (!read(tmp, MERGE)) {
924 frontend::Alert::warning(_("Corrupt File"),
925 _("Could not read stdinsets.inc! This may lead to data loss!"));
930 min_toclevel_ = Layout::NOT_IN_TOC;
931 max_toclevel_ = Layout::NOT_IN_TOC;
932 const_iterator lit = begin();
933 const_iterator len = end();
934 for (; lit != len; ++lit) {
935 int const toclevel = lit->toclevel;
936 if (toclevel != Layout::NOT_IN_TOC) {
937 if (min_toclevel_ == Layout::NOT_IN_TOC)
938 min_toclevel_ = toclevel;
940 min_toclevel_ = min(min_toclevel_, toclevel);
941 max_toclevel_ = max(max_toclevel_, toclevel);
944 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
945 << ", maximum is " << max_toclevel_);
947 return (error ? ERROR : OK);
951 void TextClass::readTitleType(Lexer & lexrc)
953 LexerKeyword titleTypeTags[] = {
954 { "commandafter", TITLE_COMMAND_AFTER },
955 { "environment", TITLE_ENVIRONMENT }
958 PushPopHelper pph(lexrc, titleTypeTags);
960 int le = lexrc.lex();
962 case Lexer::LEX_UNDEF:
963 lexrc.printError("Unknown output type `$$Token'");
965 case TITLE_COMMAND_AFTER:
966 case TITLE_ENVIRONMENT:
967 titletype_ = static_cast<TitleLatexType>(le);
970 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
976 void TextClass::readOutputType(Lexer & lexrc)
978 LexerKeyword outputTypeTags[] = {
979 { "docbook", DOCBOOK },
981 { "literate", LITERATE }
984 PushPopHelper pph(lexrc, outputTypeTags);
986 int le = lexrc.lex();
988 case Lexer::LEX_UNDEF:
989 lexrc.printError("Unknown output type `$$Token'");
994 outputType_ = static_cast<OutputType>(le);
997 LYXERR0("Unhandled value " << le);
1003 void TextClass::readClassOptions(Lexer & lexrc)
1016 LexerKeyword classOptionsTags[] = {
1018 {"fontsize", CO_FONTSIZE },
1019 {"fontsizeformat", CO_FONTSIZE_FORMAT },
1020 {"header", CO_HEADER },
1021 {"other", CO_OTHER },
1022 {"pagesize", CO_PAGESIZE },
1023 {"pagesizeformat", CO_PAGESIZE_FORMAT },
1024 {"pagestyle", CO_PAGESTYLE }
1027 lexrc.pushTable(classOptionsTags);
1028 bool getout = false;
1029 while (!getout && lexrc.isOK()) {
1030 int le = lexrc.lex();
1032 case Lexer::LEX_UNDEF:
1033 lexrc.printError("Unknown ClassOption tag `$$Token'");
1041 opt_fontsize_ = rtrim(lexrc.getString());
1043 case CO_FONTSIZE_FORMAT:
1045 fontsize_format_ = rtrim(lexrc.getString());
1049 opt_pagesize_ = rtrim(lexrc.getString());
1051 case CO_PAGESIZE_FORMAT:
1053 pagesize_format_ = rtrim(lexrc.getString());
1057 opt_pagestyle_ = rtrim(lexrc.getString());
1061 if (options_.empty())
1062 options_ = lexrc.getString();
1064 options_ += ',' + lexrc.getString();
1068 class_header_ = subst(lexrc.getString(), """, "\"");
1079 vector<CitationStyle> const & TextClass::getCiteStyles(
1080 CiteEngineType const & type) const
1082 static vector<CitationStyle> empty;
1083 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1084 if (it == cite_styles_.end())
1090 bool TextClass::readCiteEngine(Lexer & lexrc, ReadType rt, bool const add)
1092 int const type = readCiteEngineType(lexrc);
1093 bool authoryear = (type & ENGINE_TYPE_AUTHORYEAR);
1094 bool numerical = (type & ENGINE_TYPE_NUMERICAL);
1095 bool defce = (type & ENGINE_TYPE_DEFAULT);
1097 if (rt == CITE_ENGINE) {
1098 // The cite engines are not supposed to overwrite
1099 // CiteStyle defined by the class or a module.
1101 authoryear = getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1103 numerical = getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1105 defce = getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1108 if (rt != CITE_ENGINE && !add) {
1109 // Reset if we defined CiteStyle
1110 // from the class or a module
1112 cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1114 cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1116 cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1120 bool getout = false;
1121 while (!getout && lexrc.isOK()) {
1123 def = lexrc.getString();
1124 def = subst(def, " ", "");
1125 def = subst(def, "\t", "");
1126 if (compare_ascii_no_case(def, "end") == 0) {
1131 char ichar = def[0];
1134 if (isUpperCase(ichar)) {
1135 cs.forceUpperCase = true;
1136 def[0] = lowercase(ichar);
1139 /** For portability reasons (between different
1140 * cite engines such as natbib and biblatex),
1141 * we distinguish between:
1142 * 1. The LyX name as output in the LyX file
1143 * 2. Possible aliases that might fall back to
1144 * the given LyX name in the current engine
1145 * 3. The actual LaTeX command that is output
1146 * (2) and (3) are optional.
1147 * Also, the GUI string for the starred version can
1150 * LyXName|alias,nextalias*<!stardesc!stardesctooltip>[][]=latexcmd
1159 ScanMode mode = LyXName;
1160 ScanMode oldmode = LyXName;
1165 size_t const n = def.size();
1166 for (size_t i = 0; i != n; ++i) {
1170 else if (ichar == '=')
1172 else if (ichar == '<') {
1175 } else if (ichar == '>')
1177 else if (mode == LaTeXCmd)
1179 else if (mode == StarDesc)
1181 else if (ichar == '$')
1182 cs.hasQualifiedList = true;
1183 else if (ichar == '*')
1184 cs.hasStarredVersion = true;
1185 else if (ichar == '[' && cs.textAfter)
1186 cs.textBefore = true;
1187 else if (ichar == '[')
1188 cs.textAfter = true;
1189 else if (ichar != ']') {
1197 cs.cmd = latex_cmd.empty() ? lyx_cmd : latex_cmd;
1198 if (!alias.empty()) {
1199 vector<string> const aliases = getVectorFromString(alias);
1200 for (string const &s: aliases)
1201 cite_command_aliases_[s] = lyx_cmd;
1203 vector<string> const stardescs = getVectorFromString(stardesc, "!");
1204 int size = int(stardesc.size());
1206 cs.stardesc = stardescs[0];
1208 cs.startooltip = stardescs[1];
1211 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1213 class_cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1215 class_cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1218 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1220 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1222 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1225 // If we do AddToCiteEngine, do not apply yet,
1226 // except if we have already a style to add something to
1227 bool apply_ay = !add;
1228 bool apply_num = !add;
1229 bool apply_def = !add;
1231 if (type & ENGINE_TYPE_AUTHORYEAR)
1232 apply_ay = !getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1233 if (type & ENGINE_TYPE_NUMERICAL)
1234 apply_num = !getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1235 if (type & ENGINE_TYPE_DEFAULT)
1236 apply_def = !getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1239 // Add the styles from AddToCiteEngine to the class' styles
1240 // (but only if they are not yet defined)
1241 for (auto const & cis : class_cite_styles_) {
1242 // Only consider the current CiteEngineType
1243 if (!(type & cis.first))
1245 for (auto const & ciss : cis.second) {
1246 bool defined = false;
1247 // Check if the style "name" is already def'ed
1248 for (auto const & av : getCiteStyles(cis.first))
1249 if (av.name == ciss.name)
1252 if (cis.first == ENGINE_TYPE_AUTHORYEAR && apply_ay)
1253 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(ciss);
1254 else if (cis.first == ENGINE_TYPE_NUMERICAL && apply_num)
1255 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(ciss);
1256 else if (cis.first == ENGINE_TYPE_DEFAULT && apply_def)
1257 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(ciss);
1261 if (type & ENGINE_TYPE_AUTHORYEAR && apply_ay)
1262 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1263 if (type & ENGINE_TYPE_NUMERICAL && apply_num)
1264 class_cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1265 if (type & ENGINE_TYPE_DEFAULT && apply_def)
1266 class_cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1271 int TextClass::readCiteEngineType(Lexer & lexrc) const
1273 static_assert(ENGINE_TYPE_DEFAULT ==
1274 (ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL),
1275 "Incorrect default engine type");
1276 if (!lexrc.next()) {
1277 lexrc.printError("No cite engine type given for token: `$$Token'.");
1278 return ENGINE_TYPE_DEFAULT;
1280 string const type = rtrim(lexrc.getString());
1281 if (compare_ascii_no_case(type, "authoryear") == 0)
1282 return ENGINE_TYPE_AUTHORYEAR;
1283 else if (compare_ascii_no_case(type, "numerical") == 0)
1284 return ENGINE_TYPE_NUMERICAL;
1285 else if (compare_ascii_no_case(type, "default") != 0) {
1286 string const s = "Unknown cite engine type `" + type
1287 + "' given for token: `$$Token',";
1288 lexrc.printError(s);
1290 return ENGINE_TYPE_DEFAULT;
1294 bool TextClass::readCiteFormat(Lexer & lexrc, ReadType rt)
1296 int const type = readCiteEngineType(lexrc);
1299 // Cite engine definitions do not overwrite existing
1300 // definitions from the class or a module
1301 bool const overwrite = rt != CITE_ENGINE;
1302 while (lexrc.isOK()) {
1304 etype = lexrc.getString();
1305 if (compare_ascii_no_case(etype, "end") == 0)
1310 definition = lexrc.getString();
1311 char initchar = etype[0];
1312 if (initchar == '#')
1314 if (initchar == '!' || initchar == '_' || prefixIs(etype, "B_")) {
1315 bool defined = false;
1316 bool aydefined = false;
1317 bool numdefined = false;
1318 // Check if the macro is already def'ed
1319 for (auto const & cm : cite_macros_) {
1320 if (!(type & cm.first))
1322 if (cm.second.find(etype) != cm.second.end()) {
1323 if (type == cm.first)
1324 // defined as default or specific type
1326 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1327 // defined for author-year
1329 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1330 // defined for numerical
1334 if (!defined || overwrite) {
1335 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1336 cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1337 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1338 cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1339 if (type == ENGINE_TYPE_DEFAULT)
1340 cite_macros_[ENGINE_TYPE_DEFAULT][etype] = definition;
1343 bool defined = false;
1344 bool aydefined = false;
1345 bool numdefined = false;
1346 // Check if the format is already def'ed
1347 for (auto const & cm : cite_formats_) {
1348 if (!(type & cm.first))
1350 if (cm.second.find(etype) != cm.second.end()) {
1351 if (type == cm.first)
1352 // defined as default or specific type
1354 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1355 // defined for author-year
1357 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1358 // defined for numerical
1362 if (!defined || overwrite){
1363 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1364 cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1365 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1366 cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1367 if (type == ENGINE_TYPE_DEFAULT)
1368 cite_formats_[ENGINE_TYPE_DEFAULT][etype] = definition;
1376 bool TextClass::readFloat(Lexer & lexrc)
1393 FT_ALLOWED_PLACEMENT,
1400 LexerKeyword floatTags[] = {
1401 { "allowedplacement", FT_ALLOWED_PLACEMENT },
1402 { "allowssideways", FT_ALLOWS_SIDEWAYS },
1403 { "allowswide", FT_ALLOWS_WIDE },
1405 { "extension", FT_EXT },
1406 { "guiname", FT_NAME },
1407 { "htmlattr", FT_HTMLATTR },
1408 { "htmlstyle", FT_HTMLSTYLE },
1409 { "htmltag", FT_HTMLTAG },
1410 { "ispredefined", FT_PREDEFINED },
1411 { "listcommand", FT_LISTCOMMAND },
1412 { "listname", FT_LISTNAME },
1413 { "numberwithin", FT_WITHIN },
1414 { "placement", FT_PLACEMENT },
1415 { "refprefix", FT_REFPREFIX },
1416 { "requires", FT_REQUIRES },
1417 { "style", FT_STYLE },
1418 { "type", FT_TYPE },
1419 { "usesfloatpkg", FT_USESFLOAT }
1422 lexrc.pushTable(floatTags);
1426 docstring htmlstyle;
1432 string allowed_placement = "!htbpH";
1438 bool usesfloat = true;
1439 bool ispredefined = false;
1440 bool allowswide = true;
1441 bool allowssideways = true;
1443 bool getout = false;
1444 while (!getout && lexrc.isOK()) {
1445 int le = lexrc.lex();
1447 case Lexer::LEX_UNDEF:
1448 lexrc.printError("Unknown float tag `$$Token'");
1456 type = lexrc.getString();
1457 if (floatlist_.typeExist(type)) {
1458 Floating const & fl = floatlist_.getType(type);
1459 placement = fl.placement();
1461 within = fl.within();
1464 listname = fl.listName();
1465 usesfloat = fl.usesFloatPkg();
1466 ispredefined = fl.isPredefined();
1467 listcommand = fl.listCommand();
1468 refprefix = fl.refPrefix();
1473 name = lexrc.getString();
1477 placement = lexrc.getString();
1479 case FT_ALLOWED_PLACEMENT:
1481 allowed_placement = lexrc.getString();
1485 ext = lexrc.getString();
1489 within = lexrc.getString();
1490 if (within == "none")
1495 style = lexrc.getString();
1497 case FT_LISTCOMMAND:
1499 listcommand = lexrc.getString();
1503 refprefix = lexrc.getString();
1507 listname = lexrc.getString();
1511 usesfloat = lexrc.getBool();
1515 requires = lexrc.getString();
1519 ispredefined = lexrc.getBool();
1521 case FT_ALLOWS_SIDEWAYS:
1523 allowssideways = lexrc.getBool();
1525 case FT_ALLOWS_WIDE:
1527 allowswide = lexrc.getBool();
1531 htmlattr = lexrc.getString();
1535 htmlstyle = lexrc.getLongString(from_ascii("EndHTMLStyle"));
1539 htmltag = lexrc.getString();
1549 // Here we have a full float if getout == true
1551 if (!usesfloat && listcommand.empty()) {
1552 // if this float uses the same auxfile as an existing one,
1553 // there is no need for it to provide a list command.
1554 FloatList::const_iterator it = floatlist_.begin();
1555 FloatList::const_iterator en = floatlist_.end();
1556 bool found_ext = false;
1557 for (; it != en; ++it) {
1558 if (it->second.ext() == ext) {
1564 LYXERR0("The layout does not provide a list command " <<
1565 "for the float `" << type << "'. LyX will " <<
1566 "not be able to produce a float list.");
1568 Floating fl(type, placement, ext, within, style, name,
1569 listname, listcommand, refprefix, allowed_placement,
1570 htmltag, htmlattr, htmlstyle, requires, usesfloat,
1571 ispredefined, allowswide, allowssideways);
1572 floatlist_.newFloat(fl);
1573 // each float has its own counter
1574 counters_.newCounter(from_ascii(type), from_ascii(within),
1575 docstring(), docstring());
1576 // also define sub-float counters
1577 docstring const subtype = "sub-" + from_ascii(type);
1578 counters_.newCounter(subtype, from_ascii(type),
1579 "\\alph{" + subtype + "}", docstring());
1585 bool TextClass::readOutlinerName(Lexer & lexrc)
1590 type = lexrc.getString();
1592 lexrc.printError("No type given for OutlinerName: `$$Token'.");
1596 name = lexrc.getDocString();
1598 lexrc.printError("No name given for OutlinerName: `$$Token'.");
1601 outliner_names_[type] = name;
1606 string const & TextClass::prerequisites(string const & sep) const
1608 if (contains(prerequisites_, ',')) {
1609 vector<string> const pres = getVectorFromString(prerequisites_);
1610 prerequisites_ = getStringFromVector(pres, sep);
1612 return prerequisites_;
1616 bool TextClass::hasLayout(docstring const & n) const
1618 docstring const name = n.empty() ? defaultLayoutName() : n;
1620 return find_if(layoutlist_.begin(), layoutlist_.end(),
1621 LayoutNamesEqual(name))
1622 != layoutlist_.end();
1626 bool TextClass::hasInsetLayout(docstring const & n) const
1630 InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
1631 return it != insetlayoutlist_.end();
1635 Layout const & TextClass::operator[](docstring const & name) const
1637 LATTEST(!name.empty());
1640 find_if(begin(), end(), LayoutNamesEqual(name));
1643 LYXERR0("We failed to find the layout '" << name
1644 << "' in the layout list. You MUST investigate!");
1645 for (const_iterator cit = begin(); cit != end(); ++cit)
1646 lyxerr << " " << to_utf8(cit->name()) << endl;
1648 // We require the name to exist
1649 static const Layout dummy;
1650 LASSERT(false, return dummy);
1657 Layout & TextClass::operator[](docstring const & name)
1659 LATTEST(!name.empty());
1660 // Safe to continue, given what we do below.
1662 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1665 LYXERR0("We failed to find the layout '" << to_utf8(name)
1666 << "' in the layout list. You MUST investigate!");
1667 for (const_iterator cit = begin(); cit != end(); ++cit)
1668 LYXERR0(" " << to_utf8(cit->name()));
1670 // we require the name to exist
1672 // we are here only in release mode
1673 layoutlist_.push_back(createBasicLayout(name, true));
1674 it = find_if(begin(), end(), LayoutNamesEqual(name));
1681 bool TextClass::deleteLayout(docstring const & name)
1683 if (name == defaultLayoutName() || name == plainLayoutName())
1686 LayoutList::iterator it =
1687 remove_if(layoutlist_.begin(), layoutlist_.end(),
1688 LayoutNamesEqual(name));
1690 LayoutList::iterator end = layoutlist_.end();
1691 bool const ret = (it != end);
1692 layoutlist_.erase(it, end);
1697 bool TextClass::deleteInsetLayout(docstring const & name)
1699 return insetlayoutlist_.erase(name);
1703 // Load textclass info if not loaded yet
1704 bool TextClass::load(string const & path) const
1709 // Read style-file, provided path is searched before the system ones
1710 // If path is a file, it is loaded directly.
1711 FileName layout_file(path);
1712 if (!path.empty() && !layout_file.isReadableFile())
1713 layout_file = FileName(addName(path, name_ + ".layout"));
1714 if (layout_file.empty() || !layout_file.exists())
1715 layout_file = libFileSearch("layouts", name_, "layout");
1716 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1719 lyxerr << "Error reading `"
1720 << to_utf8(makeDisplayPath(layout_file.absFileName()))
1721 << "'\n(Check `" << name_
1722 << "')\nCheck your installation and "
1723 "try Options/Reconfigure..."
1731 bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
1736 layoutlist_.push_back(createBasicLayout(n, true));
1741 string DocumentClass::forcedLayouts() const
1745 const_iterator const e = end();
1746 for (const_iterator i = begin(); i != e; ++i) {
1747 if (i->forcelocal > 0) {
1749 os << "Format " << LAYOUT_FORMAT << '\n';
1759 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1761 // FIXME The fix for the InsetLayout part of 4812 would be here:
1762 // Add the InsetLayout to the document class if it is not found.
1764 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1765 while (!n.empty()) {
1766 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1767 if (cit != cen && cit->first == n) {
1768 if (cit->second.obsoleted_by().empty())
1770 n = cit->second.obsoleted_by();
1771 return insetLayout(n);
1773 // If we have a generic prefix (e.g., "Note:"),
1774 // try if this one alone is found.
1775 size_t i = n.find(':');
1776 if (i == string::npos)
1780 // Layout "name" not found.
1781 return plainInsetLayout();
1785 InsetLayout const & DocumentClass::plainInsetLayout() {
1786 static const InsetLayout plain_insetlayout_;
1787 return plain_insetlayout_;
1791 docstring const & TextClass::defaultLayoutName() const
1793 return defaultlayout_;
1797 Layout const & TextClass::defaultLayout() const
1799 return operator[](defaultLayoutName());
1803 bool TextClass::isDefaultLayout(Layout const & layout) const
1805 return layout.name() == defaultLayoutName();
1809 bool TextClass::isPlainLayout(Layout const & layout) const
1811 return layout.name() == plainLayoutName();
1815 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1817 static Layout * defaultLayout = NULL;
1819 if (defaultLayout) {
1820 defaultLayout->setUnknown(unknown);
1821 defaultLayout->setName(name);
1822 return *defaultLayout;
1825 static char const * s = "Margin Static\n"
1826 "LatexType Paragraph\n"
1829 "AlignPossible Left, Right, Center\n"
1830 "LabelType No_Label\n"
1832 istringstream ss(s);
1833 Lexer lex(textClassTags);
1835 defaultLayout = new Layout;
1836 defaultLayout->setUnknown(unknown);
1837 defaultLayout->setName(name);
1838 if (!readStyle(lex, *defaultLayout)) {
1839 // The only way this happens is because the hardcoded layout above
1843 return *defaultLayout;
1847 DocumentClassPtr getDocumentClass(
1848 LayoutFile const & baseClass, LayoutModuleList const & modlist,
1849 string const & cengine, bool const clone)
1851 DocumentClassPtr doc_class =
1852 DocumentClassPtr(new DocumentClass(baseClass));
1853 LayoutModuleList::const_iterator it = modlist.begin();
1854 LayoutModuleList::const_iterator en = modlist.end();
1855 for (; it != en; ++it) {
1856 string const modName = *it;
1857 LyXModule * lm = theModuleList[modName];
1859 docstring const msg =
1860 bformat(_("The module %1$s has been requested by\n"
1861 "this document but has not been found in the list of\n"
1862 "available modules. If you recently installed it, you\n"
1863 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1865 frontend::Alert::warning(_("Module not available"), msg);
1868 if (!lm->isAvailable() && !clone) {
1869 docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
1870 docstring const msg =
1871 bformat(_("The module %1$s requires a package that is not\n"
1872 "available in your LaTeX installation, or a converter that\n"
1873 "you have not installed. LaTeX output may not be possible.\n"
1874 "Missing prerequisites:\n"
1876 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1877 from_utf8(modName), prereqs);
1878 frontend::Alert::warning(_("Package not available"), msg, true);
1880 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1881 if (!doc_class->read(layout_file, TextClass::MODULE)) {
1882 docstring const msg =
1883 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1884 frontend::Alert::warning(_("Read Error"), msg);
1888 if (cengine.empty())
1891 LyXCiteEngine * ce = theCiteEnginesList[cengine];
1893 docstring const msg =
1894 bformat(_("The cite engine %1$s has been requested by\n"
1895 "this document but has not been found in the list of\n"
1896 "available engines. If you recently installed it, you\n"
1897 "probably need to reconfigure LyX.\n"), from_utf8(cengine));
1899 frontend::Alert::warning(_("Cite Engine not available"), msg);
1900 } else if (!ce->isAvailable() && !clone) {
1901 docstring const prereqs = from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
1902 docstring const msg =
1903 bformat(_("The cite engine %1$s requires a package that is not\n"
1904 "available in your LaTeX installation, or a converter that\n"
1905 "you have not installed. LaTeX output may not be possible.\n"
1906 "Missing prerequisites:\n"
1908 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1909 from_utf8(cengine), prereqs);
1910 frontend::Alert::warning(_("Package not available"), msg, true);
1912 FileName layout_file = libFileSearch("citeengines", ce->getFilename());
1913 if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
1914 docstring const msg =
1915 bformat(_("Error reading cite engine %1$s\n"), from_utf8(cengine));
1916 frontend::Alert::warning(_("Read Error"), msg);
1924 /////////////////////////////////////////////////////////////////////////
1928 /////////////////////////////////////////////////////////////////////////
1930 DocumentClass::DocumentClass(LayoutFile const & tc)
1935 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1937 LayoutList::const_iterator it = layoutlist_.begin();
1938 LayoutList::const_iterator end = layoutlist_.end();
1939 for (; it != end; ++it)
1940 if (it->latexname() == lay)
1946 bool DocumentClass::provides(string const & p) const
1948 return provides_.find(p) != provides_.end();
1952 bool DocumentClass::hasTocLevels() const
1954 return min_toclevel_ != Layout::NOT_IN_TOC;
1958 Layout const & DocumentClass::getTOCLayout() const
1960 // we're going to look for the layout with the minimum toclevel
1961 TextClass::LayoutList::const_iterator lit = begin();
1962 TextClass::LayoutList::const_iterator const len = end();
1963 int minlevel = 1000;
1964 Layout const * lay = NULL;
1965 for (; lit != len; ++lit) {
1966 int const level = lit->toclevel;
1967 // we don't want Part or unnumbered sections
1968 if (level == Layout::NOT_IN_TOC || level < 0
1969 || level >= minlevel || lit->counter.empty())
1976 // hmm. that is very odd, so we'll do our best.
1977 return operator[](defaultLayoutName());
1981 Layout const & DocumentClass::htmlTOCLayout() const
1983 if (html_toc_section_.empty())
1984 html_toc_section_ = getTOCLayout().name();
1985 return operator[](html_toc_section_);
1989 string const DocumentClass::getCiteFormat(CiteEngineType const & type,
1990 string const & entry, bool const punct, string const & fallback) const
1992 string default_format = "{%fullnames:author%[[%fullnames:author%, ]][[{%fullnames:editor%[[%fullnames:editor%, ed., ]]}]]}"
1993 "\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]]"
1994 "[[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}";
1996 default_format += ".";
1998 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
1999 if (itype == cite_formats_.end())
2000 return default_format;
2001 map<string, string>::const_iterator it = itype->second.find(entry);
2002 if (it == itype->second.end() && !fallback.empty())
2003 it = itype->second.find(fallback);
2004 if (it == itype->second.end())
2005 return default_format;
2007 return it->second + ".";
2012 string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
2013 string const & macro) const
2015 static string empty;
2016 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
2017 if (itype == cite_macros_.end())
2019 map<string, string>::const_iterator it = itype->second.find(macro);
2020 if (it == itype->second.end())
2026 vector<string> const DocumentClass::citeCommands(
2027 CiteEngineType const & type) const
2029 vector<CitationStyle> const styles = citeStyles(type);
2030 vector<CitationStyle>::const_iterator it = styles.begin();
2031 vector<CitationStyle>::const_iterator end = styles.end();
2032 vector<string> cmds;
2033 for (; it != end; ++it) {
2034 CitationStyle const cite = *it;
2035 cmds.push_back(cite.name);
2041 vector<CitationStyle> const & DocumentClass::citeStyles(
2042 CiteEngineType const & type) const
2044 static vector<CitationStyle> empty;
2045 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
2046 if (it == cite_styles_.end())
2052 /////////////////////////////////////////////////////////////////////////
2056 /////////////////////////////////////////////////////////////////////////
2058 ostream & operator<<(ostream & os, PageSides p)