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(), '_', ' ');
748 bool const validating = (rt == VALIDATION);
750 string s = "Could not read name for InsetLayout: `$$Token' "
751 + lexrc.getString() + " is probably not valid UTF-8!";
754 // Since we couldn't read the name, we just scan the rest
755 // of the style and discard it.
756 il.read(lexrc, *this);
757 // Let's try to continue rather than abort, unless we're validating
758 // in which case we want to report the error
761 } else if (hasInsetLayout(name)) {
762 InsetLayout & il = insetlayoutlist_[name];
763 error = !il.read(lexrc, *this, validating);
767 error = !il.read(lexrc, *this, validating);
769 insetlayoutlist_[name] = il;
775 error = !readFloat(lexrc);
779 error = !readCiteEngine(lexrc, rt);
782 case TC_ADDTOCITEENGINE:
783 error = !readCiteEngine(lexrc, rt, true);
786 case TC_CITEENGINETYPE:
788 opt_enginetype_ = rtrim(lexrc.getString());
792 error = !readCiteFormat(lexrc, rt);
795 case TC_CITEFRAMEWORK:
797 citeframework_ = rtrim(lexrc.getString());
800 case TC_MAXCITENAMES:
802 maxcitenames_ = size_t(lexrc.getInteger());
805 case TC_DEFAULTBIBLIO:
807 vector<string> const dbs =
808 getVectorFromString(rtrim(lexrc.getString()), "|");
809 vector<string>::const_iterator it = dbs.begin();
810 vector<string>::const_iterator end = dbs.end();
811 for (; it != end; ++it) {
812 if (!contains(*it, ':')) {
813 vector<string> const enginetypes =
814 getVectorFromString(opt_enginetype_, "|");
815 for (string const &s: enginetypes)
816 cite_default_biblio_style_[s] = *it;
819 string const db = split(*it, eng, ':');
820 cite_default_biblio_style_[eng] = db;
828 bibintoc_ = lexrc.getBool();
831 case TC_FULLAUTHORLIST:
833 cite_full_author_list_ &= lexrc.getBool();
838 docstring const cnt = lexrc.getDocString();
839 if (!counters_.remove(cnt))
840 LYXERR0("Unable to remove counter: " + to_utf8(cnt));
849 docstring const name = lexrc.getDocString();
851 string s = "Could not read name for counter: `$$Token' "
852 + lexrc.getString() + " is probably not valid UTF-8!";
853 lexrc.printError(s.c_str());
855 // Since we couldn't read the name, we just scan the rest
859 error = !counters_.read(lexrc, name, !ifcounter);
862 lexrc.printError("No name given for style: `$$Token'.");
867 case TC_TITLELATEXTYPE:
868 readTitleType(lexrc);
871 case TC_TITLELATEXNAME:
873 titlename_ = lexrc.getString();
878 string const nofloat = lexrc.getString();
879 floatlist_.erase(nofloat);
883 case TC_OUTLINERNAME:
884 error = !readOutlinerName(lexrc);
889 tablestyle_ = rtrim(lexrc.getString());
894 // at present, we abort if we encounter an error,
895 // so there is no point continuing.
902 if (defaultlayout_.empty()) {
903 LYXERR0("Error: Textclass '" << name_
904 << "' is missing a defaultstyle.");
908 // Try to erase "stdinsets" from the provides_ set.
910 // Provides stdinsets 1
911 // declaration simply tells us that the standard insets have been
912 // defined. (It's found in stdinsets.inc but could also be used in
913 // user-defined files.) There isn't really any such package. So we
914 // might as well go ahead and erase it.
915 // If we do not succeed, then it was not there, which means that
916 // the textclass did not provide the definitions of the standard
917 // insets. So we need to try to load them.
918 int erased = provides_.erase("stdinsets");
920 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
923 frontend::Alert::warning(_("Missing File"),
924 _("Could not find stdinsets.inc! This may lead to data loss!"));
926 } else if (!read(tmp, MERGE)) {
927 frontend::Alert::warning(_("Corrupt File"),
928 _("Could not read stdinsets.inc! This may lead to data loss!"));
933 min_toclevel_ = Layout::NOT_IN_TOC;
934 max_toclevel_ = Layout::NOT_IN_TOC;
935 const_iterator lit = begin();
936 const_iterator len = end();
937 for (; lit != len; ++lit) {
938 int const toclevel = lit->toclevel;
939 if (toclevel != Layout::NOT_IN_TOC) {
940 if (min_toclevel_ == Layout::NOT_IN_TOC)
941 min_toclevel_ = toclevel;
943 min_toclevel_ = min(min_toclevel_, toclevel);
944 max_toclevel_ = max(max_toclevel_, toclevel);
947 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
948 << ", maximum is " << max_toclevel_);
950 return (error ? ERROR : OK);
954 void TextClass::readTitleType(Lexer & lexrc)
956 LexerKeyword titleTypeTags[] = {
957 { "commandafter", TITLE_COMMAND_AFTER },
958 { "environment", TITLE_ENVIRONMENT }
961 PushPopHelper pph(lexrc, titleTypeTags);
963 int le = lexrc.lex();
965 case Lexer::LEX_UNDEF:
966 lexrc.printError("Unknown output type `$$Token'");
968 case TITLE_COMMAND_AFTER:
969 case TITLE_ENVIRONMENT:
970 titletype_ = static_cast<TitleLatexType>(le);
973 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
979 void TextClass::readOutputType(Lexer & lexrc)
981 LexerKeyword outputTypeTags[] = {
982 { "docbook", DOCBOOK },
984 { "literate", LITERATE }
987 PushPopHelper pph(lexrc, outputTypeTags);
989 int le = lexrc.lex();
991 case Lexer::LEX_UNDEF:
992 lexrc.printError("Unknown output type `$$Token'");
997 outputType_ = static_cast<OutputType>(le);
1000 LYXERR0("Unhandled value " << le);
1006 void TextClass::readClassOptions(Lexer & lexrc)
1019 LexerKeyword classOptionsTags[] = {
1021 {"fontsize", CO_FONTSIZE },
1022 {"fontsizeformat", CO_FONTSIZE_FORMAT },
1023 {"header", CO_HEADER },
1024 {"other", CO_OTHER },
1025 {"pagesize", CO_PAGESIZE },
1026 {"pagesizeformat", CO_PAGESIZE_FORMAT },
1027 {"pagestyle", CO_PAGESTYLE }
1030 lexrc.pushTable(classOptionsTags);
1031 bool getout = false;
1032 while (!getout && lexrc.isOK()) {
1033 int le = lexrc.lex();
1035 case Lexer::LEX_UNDEF:
1036 lexrc.printError("Unknown ClassOption tag `$$Token'");
1044 opt_fontsize_ = rtrim(lexrc.getString());
1046 case CO_FONTSIZE_FORMAT:
1048 fontsize_format_ = rtrim(lexrc.getString());
1052 opt_pagesize_ = rtrim(lexrc.getString());
1054 case CO_PAGESIZE_FORMAT:
1056 pagesize_format_ = rtrim(lexrc.getString());
1060 opt_pagestyle_ = rtrim(lexrc.getString());
1064 if (options_.empty())
1065 options_ = lexrc.getString();
1067 options_ += ',' + lexrc.getString();
1071 class_header_ = subst(lexrc.getString(), """, "\"");
1082 vector<CitationStyle> const & TextClass::getCiteStyles(
1083 CiteEngineType const & type) const
1085 static vector<CitationStyle> empty;
1086 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
1087 if (it == cite_styles_.end())
1093 bool TextClass::readCiteEngine(Lexer & lexrc, ReadType rt, bool const add)
1095 int const type = readCiteEngineType(lexrc);
1096 bool authoryear = (type & ENGINE_TYPE_AUTHORYEAR);
1097 bool numerical = (type & ENGINE_TYPE_NUMERICAL);
1098 bool defce = (type & ENGINE_TYPE_DEFAULT);
1100 if (rt == CITE_ENGINE) {
1101 // The cite engines are not supposed to overwrite
1102 // CiteStyle defined by the class or a module.
1104 authoryear = getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1106 numerical = getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1108 defce = getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1111 if (rt != CITE_ENGINE && !add) {
1112 // Reset if we defined CiteStyle
1113 // from the class or a module
1115 cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1117 cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1119 cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1123 bool getout = false;
1124 while (!getout && lexrc.isOK()) {
1126 def = lexrc.getString();
1127 def = subst(def, " ", "");
1128 def = subst(def, "\t", "");
1129 if (compare_ascii_no_case(def, "end") == 0) {
1134 char ichar = def[0];
1137 if (isUpperCase(ichar)) {
1138 cs.forceUpperCase = true;
1139 def[0] = lowercase(ichar);
1142 /** For portability reasons (between different
1143 * cite engines such as natbib and biblatex),
1144 * we distinguish between:
1145 * 1. The LyX name as output in the LyX file
1146 * 2. Possible aliases that might fall back to
1147 * the given LyX name in the current engine
1148 * 3. The actual LaTeX command that is output
1149 * (2) and (3) are optional.
1150 * Also, the GUI string for the starred version can
1153 * LyXName|alias,nextalias*<!stardesc!stardesctooltip>[][]=latexcmd
1162 ScanMode mode = LyXName;
1163 ScanMode oldmode = LyXName;
1168 size_t const n = def.size();
1169 for (size_t i = 0; i != n; ++i) {
1173 else if (ichar == '=')
1175 else if (ichar == '<') {
1178 } else if (ichar == '>')
1180 else if (mode == LaTeXCmd)
1182 else if (mode == StarDesc)
1184 else if (ichar == '$')
1185 cs.hasQualifiedList = true;
1186 else if (ichar == '*')
1187 cs.hasStarredVersion = true;
1188 else if (ichar == '[' && cs.textAfter)
1189 cs.textBefore = true;
1190 else if (ichar == '[')
1191 cs.textAfter = true;
1192 else if (ichar != ']') {
1200 cs.cmd = latex_cmd.empty() ? lyx_cmd : latex_cmd;
1201 if (!alias.empty()) {
1202 vector<string> const aliases = getVectorFromString(alias);
1203 for (string const &s: aliases)
1204 cite_command_aliases_[s] = lyx_cmd;
1206 vector<string> const stardescs = getVectorFromString(stardesc, "!");
1207 int size = int(stardesc.size());
1209 cs.stardesc = stardescs[0];
1211 cs.startooltip = stardescs[1];
1214 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1216 class_cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1218 class_cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1221 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(cs);
1223 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(cs);
1225 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(cs);
1228 // If we do AddToCiteEngine, do not apply yet,
1229 // except if we have already a style to add something to
1230 bool apply_ay = !add;
1231 bool apply_num = !add;
1232 bool apply_def = !add;
1234 if (type & ENGINE_TYPE_AUTHORYEAR)
1235 apply_ay = !getCiteStyles(ENGINE_TYPE_AUTHORYEAR).empty();
1236 if (type & ENGINE_TYPE_NUMERICAL)
1237 apply_num = !getCiteStyles(ENGINE_TYPE_NUMERICAL).empty();
1238 if (type & ENGINE_TYPE_DEFAULT)
1239 apply_def = !getCiteStyles(ENGINE_TYPE_DEFAULT).empty();
1242 // Add the styles from AddToCiteEngine to the class' styles
1243 // (but only if they are not yet defined)
1244 for (auto const & cis : class_cite_styles_) {
1245 // Only consider the current CiteEngineType
1246 if (!(type & cis.first))
1248 for (auto const & ciss : cis.second) {
1249 bool defined = false;
1250 // Check if the style "name" is already def'ed
1251 for (auto const & av : getCiteStyles(cis.first))
1252 if (av.name == ciss.name)
1255 if (cis.first == ENGINE_TYPE_AUTHORYEAR && apply_ay)
1256 cite_styles_[ENGINE_TYPE_AUTHORYEAR].push_back(ciss);
1257 else if (cis.first == ENGINE_TYPE_NUMERICAL && apply_num)
1258 cite_styles_[ENGINE_TYPE_NUMERICAL].push_back(ciss);
1259 else if (cis.first == ENGINE_TYPE_DEFAULT && apply_def)
1260 cite_styles_[ENGINE_TYPE_DEFAULT].push_back(ciss);
1264 if (type & ENGINE_TYPE_AUTHORYEAR && apply_ay)
1265 class_cite_styles_[ENGINE_TYPE_AUTHORYEAR].clear();
1266 if (type & ENGINE_TYPE_NUMERICAL && apply_num)
1267 class_cite_styles_[ENGINE_TYPE_NUMERICAL].clear();
1268 if (type & ENGINE_TYPE_DEFAULT && apply_def)
1269 class_cite_styles_[ENGINE_TYPE_DEFAULT].clear();
1274 int TextClass::readCiteEngineType(Lexer & lexrc) const
1276 static_assert(ENGINE_TYPE_DEFAULT ==
1277 (ENGINE_TYPE_AUTHORYEAR | ENGINE_TYPE_NUMERICAL),
1278 "Incorrect default engine type");
1279 if (!lexrc.next()) {
1280 lexrc.printError("No cite engine type given for token: `$$Token'.");
1281 return ENGINE_TYPE_DEFAULT;
1283 string const type = rtrim(lexrc.getString());
1284 if (compare_ascii_no_case(type, "authoryear") == 0)
1285 return ENGINE_TYPE_AUTHORYEAR;
1286 else if (compare_ascii_no_case(type, "numerical") == 0)
1287 return ENGINE_TYPE_NUMERICAL;
1288 else if (compare_ascii_no_case(type, "default") != 0) {
1289 string const s = "Unknown cite engine type `" + type
1290 + "' given for token: `$$Token',";
1291 lexrc.printError(s);
1293 return ENGINE_TYPE_DEFAULT;
1297 bool TextClass::readCiteFormat(Lexer & lexrc, ReadType rt)
1299 int const type = readCiteEngineType(lexrc);
1302 // Cite engine definitions do not overwrite existing
1303 // definitions from the class or a module
1304 bool const overwrite = rt != CITE_ENGINE;
1305 while (lexrc.isOK()) {
1307 etype = lexrc.getString();
1308 if (compare_ascii_no_case(etype, "end") == 0)
1313 definition = lexrc.getString();
1314 char initchar = etype[0];
1315 if (initchar == '#')
1317 if (initchar == '!' || initchar == '_' || prefixIs(etype, "B_")) {
1318 bool defined = false;
1319 bool aydefined = false;
1320 bool numdefined = false;
1321 // Check if the macro is already def'ed
1322 for (auto const & cm : cite_macros_) {
1323 if (!(type & cm.first))
1325 if (cm.second.find(etype) != cm.second.end()) {
1326 if (type == cm.first)
1327 // defined as default or specific type
1329 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1330 // defined for author-year
1332 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1333 // defined for numerical
1337 if (!defined || overwrite) {
1338 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1339 cite_macros_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1340 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1341 cite_macros_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1342 if (type == ENGINE_TYPE_DEFAULT)
1343 cite_macros_[ENGINE_TYPE_DEFAULT][etype] = definition;
1346 bool defined = false;
1347 bool aydefined = false;
1348 bool numdefined = false;
1349 // Check if the format is already def'ed
1350 for (auto const & cm : cite_formats_) {
1351 if (!(type & cm.first))
1353 if (cm.second.find(etype) != cm.second.end()) {
1354 if (type == cm.first)
1355 // defined as default or specific type
1357 if (cm.first == ENGINE_TYPE_AUTHORYEAR)
1358 // defined for author-year
1360 else if (cm.first == ENGINE_TYPE_NUMERICAL)
1361 // defined for numerical
1365 if (!defined || overwrite){
1366 if (type & ENGINE_TYPE_AUTHORYEAR && (type != ENGINE_TYPE_DEFAULT || !aydefined))
1367 cite_formats_[ENGINE_TYPE_AUTHORYEAR][etype] = definition;
1368 if (type & ENGINE_TYPE_NUMERICAL && (type != ENGINE_TYPE_DEFAULT || !numdefined))
1369 cite_formats_[ENGINE_TYPE_NUMERICAL][etype] = definition;
1370 if (type == ENGINE_TYPE_DEFAULT)
1371 cite_formats_[ENGINE_TYPE_DEFAULT][etype] = definition;
1379 bool TextClass::readFloat(Lexer & lexrc)
1396 FT_ALLOWED_PLACEMENT,
1403 LexerKeyword floatTags[] = {
1404 { "allowedplacement", FT_ALLOWED_PLACEMENT },
1405 { "allowssideways", FT_ALLOWS_SIDEWAYS },
1406 { "allowswide", FT_ALLOWS_WIDE },
1408 { "extension", FT_EXT },
1409 { "guiname", FT_NAME },
1410 { "htmlattr", FT_HTMLATTR },
1411 { "htmlstyle", FT_HTMLSTYLE },
1412 { "htmltag", FT_HTMLTAG },
1413 { "ispredefined", FT_PREDEFINED },
1414 { "listcommand", FT_LISTCOMMAND },
1415 { "listname", FT_LISTNAME },
1416 { "numberwithin", FT_WITHIN },
1417 { "placement", FT_PLACEMENT },
1418 { "refprefix", FT_REFPREFIX },
1419 { "requires", FT_REQUIRES },
1420 { "style", FT_STYLE },
1421 { "type", FT_TYPE },
1422 { "usesfloatpkg", FT_USESFLOAT }
1425 lexrc.pushTable(floatTags);
1429 docstring htmlstyle;
1435 string allowed_placement = "!htbpH";
1441 bool usesfloat = true;
1442 bool ispredefined = false;
1443 bool allowswide = true;
1444 bool allowssideways = true;
1446 bool getout = false;
1447 while (!getout && lexrc.isOK()) {
1448 int le = lexrc.lex();
1450 case Lexer::LEX_UNDEF:
1451 lexrc.printError("Unknown float tag `$$Token'");
1459 type = lexrc.getString();
1460 if (floatlist_.typeExist(type)) {
1461 Floating const & fl = floatlist_.getType(type);
1462 placement = fl.placement();
1464 within = fl.within();
1467 listname = fl.listName();
1468 usesfloat = fl.usesFloatPkg();
1469 ispredefined = fl.isPredefined();
1470 listcommand = fl.listCommand();
1471 refprefix = fl.refPrefix();
1476 name = lexrc.getString();
1480 placement = lexrc.getString();
1482 case FT_ALLOWED_PLACEMENT:
1484 allowed_placement = lexrc.getString();
1488 ext = lexrc.getString();
1492 within = lexrc.getString();
1493 if (within == "none")
1498 style = lexrc.getString();
1500 case FT_LISTCOMMAND:
1502 listcommand = lexrc.getString();
1506 refprefix = lexrc.getString();
1510 listname = lexrc.getString();
1514 usesfloat = lexrc.getBool();
1518 requires = lexrc.getString();
1522 ispredefined = lexrc.getBool();
1524 case FT_ALLOWS_SIDEWAYS:
1526 allowssideways = lexrc.getBool();
1528 case FT_ALLOWS_WIDE:
1530 allowswide = lexrc.getBool();
1534 htmlattr = lexrc.getString();
1538 htmlstyle = lexrc.getLongString(from_ascii("EndHTMLStyle"));
1542 htmltag = lexrc.getString();
1552 // Here we have a full float if getout == true
1554 if (!usesfloat && listcommand.empty()) {
1555 // if this float uses the same auxfile as an existing one,
1556 // there is no need for it to provide a list command.
1557 FloatList::const_iterator it = floatlist_.begin();
1558 FloatList::const_iterator en = floatlist_.end();
1559 bool found_ext = false;
1560 for (; it != en; ++it) {
1561 if (it->second.ext() == ext) {
1567 LYXERR0("The layout does not provide a list command " <<
1568 "for the float `" << type << "'. LyX will " <<
1569 "not be able to produce a float list.");
1571 Floating fl(type, placement, ext, within, style, name,
1572 listname, listcommand, refprefix, allowed_placement,
1573 htmltag, htmlattr, htmlstyle, requires, usesfloat,
1574 ispredefined, allowswide, allowssideways);
1575 floatlist_.newFloat(fl);
1576 // each float has its own counter
1577 counters_.newCounter(from_ascii(type), from_ascii(within),
1578 docstring(), docstring());
1579 // also define sub-float counters
1580 docstring const subtype = "sub-" + from_ascii(type);
1581 counters_.newCounter(subtype, from_ascii(type),
1582 "\\alph{" + subtype + "}", docstring());
1588 bool TextClass::readOutlinerName(Lexer & lexrc)
1593 type = lexrc.getString();
1595 lexrc.printError("No type given for OutlinerName: `$$Token'.");
1599 name = lexrc.getDocString();
1601 lexrc.printError("No name given for OutlinerName: `$$Token'.");
1604 outliner_names_[type] = name;
1609 string const & TextClass::prerequisites(string const & sep) const
1611 if (contains(prerequisites_, ',')) {
1612 vector<string> const pres = getVectorFromString(prerequisites_);
1613 prerequisites_ = getStringFromVector(pres, sep);
1615 return prerequisites_;
1619 bool TextClass::hasLayout(docstring const & n) const
1621 docstring const name = n.empty() ? defaultLayoutName() : n;
1623 return find_if(layoutlist_.begin(), layoutlist_.end(),
1624 LayoutNamesEqual(name))
1625 != layoutlist_.end();
1629 bool TextClass::hasInsetLayout(docstring const & n) const
1633 InsetLayouts::const_iterator it = insetlayoutlist_.find(n);
1634 return it != insetlayoutlist_.end();
1638 Layout const & TextClass::operator[](docstring const & name) const
1640 LATTEST(!name.empty());
1643 find_if(begin(), end(), LayoutNamesEqual(name));
1646 LYXERR0("We failed to find the layout '" << name
1647 << "' in the layout list. You MUST investigate!");
1648 for (const_iterator cit = begin(); cit != end(); ++cit)
1649 lyxerr << " " << to_utf8(cit->name()) << endl;
1651 // We require the name to exist
1652 static const Layout dummy;
1653 LASSERT(false, return dummy);
1660 Layout & TextClass::operator[](docstring const & name)
1662 LATTEST(!name.empty());
1663 // Safe to continue, given what we do below.
1665 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1668 LYXERR0("We failed to find the layout '" << to_utf8(name)
1669 << "' in the layout list. You MUST investigate!");
1670 for (const_iterator cit = begin(); cit != end(); ++cit)
1671 LYXERR0(" " << to_utf8(cit->name()));
1673 // we require the name to exist
1675 // we are here only in release mode
1676 layoutlist_.push_back(createBasicLayout(name, true));
1677 it = find_if(begin(), end(), LayoutNamesEqual(name));
1684 bool TextClass::deleteLayout(docstring const & name)
1686 if (name == defaultLayoutName() || name == plainLayoutName())
1689 LayoutList::iterator it =
1690 remove_if(layoutlist_.begin(), layoutlist_.end(),
1691 LayoutNamesEqual(name));
1693 LayoutList::iterator end = layoutlist_.end();
1694 bool const ret = (it != end);
1695 layoutlist_.erase(it, end);
1700 bool TextClass::deleteInsetLayout(docstring const & name)
1702 return insetlayoutlist_.erase(name);
1706 // Load textclass info if not loaded yet
1707 bool TextClass::load(string const & path) const
1712 // Read style-file, provided path is searched before the system ones
1713 // If path is a file, it is loaded directly.
1714 FileName layout_file(path);
1715 if (!path.empty() && !layout_file.isReadableFile())
1716 layout_file = FileName(addName(path, name_ + ".layout"));
1717 if (layout_file.empty() || !layout_file.exists())
1718 layout_file = libFileSearch("layouts", name_, "layout");
1719 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1722 lyxerr << "Error reading `"
1723 << to_utf8(makeDisplayPath(layout_file.absFileName()))
1724 << "'\n(Check `" << name_
1725 << "')\nCheck your installation and "
1726 "try Options/Reconfigure..."
1734 bool DocumentClass::addLayoutIfNeeded(docstring const & n) const
1739 layoutlist_.push_back(createBasicLayout(n, true));
1744 string DocumentClass::forcedLayouts() const
1748 const_iterator const e = end();
1749 for (const_iterator i = begin(); i != e; ++i) {
1750 if (i->forcelocal > 0) {
1752 os << "Format " << LAYOUT_FORMAT << '\n';
1762 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1764 // FIXME The fix for the InsetLayout part of 4812 would be here:
1765 // Add the InsetLayout to the document class if it is not found.
1767 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1768 while (!n.empty()) {
1769 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1770 if (cit != cen && cit->first == n) {
1771 if (cit->second.obsoleted_by().empty())
1773 n = cit->second.obsoleted_by();
1774 return insetLayout(n);
1776 // If we have a generic prefix (e.g., "Note:"),
1777 // try if this one alone is found.
1778 size_t i = n.find(':');
1779 if (i == string::npos)
1783 // Layout "name" not found.
1784 return plainInsetLayout();
1788 InsetLayout const & DocumentClass::plainInsetLayout() {
1789 static const InsetLayout plain_insetlayout_;
1790 return plain_insetlayout_;
1794 docstring const & TextClass::defaultLayoutName() const
1796 return defaultlayout_;
1800 Layout const & TextClass::defaultLayout() const
1802 return operator[](defaultLayoutName());
1806 bool TextClass::isDefaultLayout(Layout const & layout) const
1808 return layout.name() == defaultLayoutName();
1812 bool TextClass::isPlainLayout(Layout const & layout) const
1814 return layout.name() == plainLayoutName();
1818 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1820 static Layout * defaultLayout = NULL;
1822 if (defaultLayout) {
1823 defaultLayout->setUnknown(unknown);
1824 defaultLayout->setName(name);
1825 return *defaultLayout;
1828 static char const * s = "Margin Static\n"
1829 "LatexType Paragraph\n"
1832 "AlignPossible Left, Right, Center\n"
1833 "LabelType No_Label\n"
1835 istringstream ss(s);
1836 Lexer lex(textClassTags);
1838 defaultLayout = new Layout;
1839 defaultLayout->setUnknown(unknown);
1840 defaultLayout->setName(name);
1841 if (!readStyle(lex, *defaultLayout)) {
1842 // The only way this happens is because the hardcoded layout above
1846 return *defaultLayout;
1850 DocumentClassPtr getDocumentClass(
1851 LayoutFile const & baseClass, LayoutModuleList const & modlist,
1852 string const & cengine, bool const clone)
1854 DocumentClassPtr doc_class =
1855 DocumentClassPtr(new DocumentClass(baseClass));
1856 LayoutModuleList::const_iterator it = modlist.begin();
1857 LayoutModuleList::const_iterator en = modlist.end();
1858 for (; it != en; ++it) {
1859 string const modName = *it;
1860 LyXModule * lm = theModuleList[modName];
1862 docstring const msg =
1863 bformat(_("The module %1$s has been requested by\n"
1864 "this document but has not been found in the list of\n"
1865 "available modules. If you recently installed it, you\n"
1866 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1868 frontend::Alert::warning(_("Module not available"), msg);
1871 if (!lm->isAvailable() && !clone) {
1872 docstring const prereqs = from_utf8(getStringFromVector(lm->prerequisites(), "\n\t"));
1873 docstring const msg =
1874 bformat(_("The module %1$s requires a package that is not\n"
1875 "available in your LaTeX installation, or a converter that\n"
1876 "you have not installed. LaTeX output may not be possible.\n"
1877 "Missing prerequisites:\n"
1879 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1880 from_utf8(modName), prereqs);
1881 frontend::Alert::warning(_("Package not available"), msg, true);
1883 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1884 if (!doc_class->read(layout_file, TextClass::MODULE)) {
1885 docstring const msg =
1886 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1887 frontend::Alert::warning(_("Read Error"), msg);
1891 if (cengine.empty())
1894 LyXCiteEngine * ce = theCiteEnginesList[cengine];
1896 docstring const msg =
1897 bformat(_("The cite engine %1$s has been requested by\n"
1898 "this document but has not been found in the list of\n"
1899 "available engines. If you recently installed it, you\n"
1900 "probably need to reconfigure LyX.\n"), from_utf8(cengine));
1902 frontend::Alert::warning(_("Cite Engine not available"), msg);
1903 } else if (!ce->isAvailable() && !clone) {
1904 docstring const prereqs = from_utf8(getStringFromVector(ce->prerequisites(), "\n\t"));
1905 docstring const msg =
1906 bformat(_("The cite engine %1$s requires a package that is not\n"
1907 "available in your LaTeX installation, or a converter that\n"
1908 "you have not installed. LaTeX output may not be possible.\n"
1909 "Missing prerequisites:\n"
1911 "See section 3.1.2.3 (Modules) of the User's Guide for more information."),
1912 from_utf8(cengine), prereqs);
1913 frontend::Alert::warning(_("Package not available"), msg, true);
1915 FileName layout_file = libFileSearch("citeengines", ce->getFilename());
1916 if (!doc_class->read(layout_file, TextClass::CITE_ENGINE)) {
1917 docstring const msg =
1918 bformat(_("Error reading cite engine %1$s\n"), from_utf8(cengine));
1919 frontend::Alert::warning(_("Read Error"), msg);
1927 /////////////////////////////////////////////////////////////////////////
1931 /////////////////////////////////////////////////////////////////////////
1933 DocumentClass::DocumentClass(LayoutFile const & tc)
1938 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1940 LayoutList::const_iterator it = layoutlist_.begin();
1941 LayoutList::const_iterator end = layoutlist_.end();
1942 for (; it != end; ++it)
1943 if (it->latexname() == lay)
1949 bool DocumentClass::provides(string const & p) const
1951 return provides_.find(p) != provides_.end();
1955 bool DocumentClass::hasTocLevels() const
1957 return min_toclevel_ != Layout::NOT_IN_TOC;
1961 Layout const & DocumentClass::getTOCLayout() const
1963 // we're going to look for the layout with the minimum toclevel
1964 TextClass::LayoutList::const_iterator lit = begin();
1965 TextClass::LayoutList::const_iterator const len = end();
1966 int minlevel = 1000;
1967 Layout const * lay = NULL;
1968 for (; lit != len; ++lit) {
1969 int const level = lit->toclevel;
1970 // we don't want Part or unnumbered sections
1971 if (level == Layout::NOT_IN_TOC || level < 0
1972 || level >= minlevel || lit->counter.empty())
1979 // hmm. that is very odd, so we'll do our best.
1980 return operator[](defaultLayoutName());
1984 Layout const & DocumentClass::htmlTOCLayout() const
1986 if (html_toc_section_.empty())
1987 html_toc_section_ = getTOCLayout().name();
1988 return operator[](html_toc_section_);
1992 string const DocumentClass::getCiteFormat(CiteEngineType const & type,
1993 string const & entry, bool const punct, string const & fallback) const
1995 string default_format = "{%fullnames:author%[[%fullnames:author%, ]][[{%fullnames:editor%[[%fullnames:editor%, ed., ]]}]]}"
1996 "\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]]"
1997 "[[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}";
1999 default_format += ".";
2001 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_formats_.find(type);
2002 if (itype == cite_formats_.end())
2003 return default_format;
2004 map<string, string>::const_iterator it = itype->second.find(entry);
2005 if (it == itype->second.end() && !fallback.empty())
2006 it = itype->second.find(fallback);
2007 if (it == itype->second.end())
2008 return default_format;
2010 return it->second + ".";
2015 string const & DocumentClass::getCiteMacro(CiteEngineType const & type,
2016 string const & macro) const
2018 static string empty;
2019 map<CiteEngineType, map<string, string> >::const_iterator itype = cite_macros_.find(type);
2020 if (itype == cite_macros_.end())
2022 map<string, string>::const_iterator it = itype->second.find(macro);
2023 if (it == itype->second.end())
2029 vector<string> const DocumentClass::citeCommands(
2030 CiteEngineType const & type) const
2032 vector<CitationStyle> const styles = citeStyles(type);
2033 vector<CitationStyle>::const_iterator it = styles.begin();
2034 vector<CitationStyle>::const_iterator end = styles.end();
2035 vector<string> cmds;
2036 for (; it != end; ++it) {
2037 CitationStyle const cite = *it;
2038 cmds.push_back(cite.name);
2044 vector<CitationStyle> const & DocumentClass::citeStyles(
2045 CiteEngineType const & type) const
2047 static vector<CitationStyle> empty;
2048 map<CiteEngineType, vector<CitationStyle> >::const_iterator it = cite_styles_.find(type);
2049 if (it == cite_styles_.end())
2055 /////////////////////////////////////////////////////////////////////////
2059 /////////////////////////////////////////////////////////////////////////
2061 ostream & operator<<(ostream & os, PageSides p)