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"
23 #include "FloatList.h"
27 #include "ModuleList.h"
29 #include "frontends/alert.h"
31 #include "support/lassert.h"
32 #include "support/debug.h"
33 #include "support/ExceptionMessage.h"
34 #include "support/FileName.h"
35 #include "support/filetools.h"
36 #include "support/gettext.h"
37 #include "support/lstrings.h"
38 #include "support/os.h"
49 using namespace lyx::support;
55 class LayoutNamesEqual : public unary_function<Layout, bool> {
57 LayoutNamesEqual(docstring const & name)
60 bool operator()(Layout const & c) const
62 return c.name() == name_;
68 // Keep the changes documented in the Customization manual.
69 int const FORMAT = 26;
72 bool layout2layout(FileName const & filename, FileName const & tempfile)
74 FileName const script = libFileSearch("scripts", "layout2layout.py");
76 LYXERR0("Could not find layout conversion "
77 "script layout2layout.py.");
81 ostringstream command;
82 command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
83 << ' ' << quoteName(filename.toFilesystemEncoding())
84 << ' ' << quoteName(tempfile.toFilesystemEncoding());
85 string const command_str = command.str();
87 LYXERR(Debug::TCLASS, "Running `" << command_str << '\'');
89 cmd_ret const ret = runCommand(command_str);
91 LYXERR0("Could not run layout conversion script layout2layout.py.");
98 string translateRT(TextClass::ReadType rt)
101 case TextClass::BASECLASS:
103 case TextClass::MERGE:
105 case TextClass::MODULE:
106 return "module file";
107 case TextClass::VALIDATION:
117 // This string should not be translated here,
118 // because it is a layout identifier.
119 docstring const TextClass::plain_layout_ = from_ascii("Plain Layout");
122 InsetLayout DocumentClass::plain_insetlayout_;
125 /////////////////////////////////////////////////////////////////////////
129 /////////////////////////////////////////////////////////////////////////
131 TextClass::TextClass()
134 outputFormat_ = "latex";
139 pagestyle_ = "default";
140 defaultfont_ = sane_font;
141 opt_fontsize_ = "10|11|12";
142 opt_pagestyle_ = "empty|plain|headings|fancy";
143 titletype_ = TITLE_COMMAND_AFTER;
144 titlename_ = "maketitle";
146 _("Plain Layout"); // a hack to make this translatable
150 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
152 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
153 if (!lay.read(lexrc, *this)) {
154 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
158 lay.resfont = lay.font;
159 lay.resfont.realize(defaultfont_);
160 lay.reslabelfont = lay.labelfont;
161 lay.reslabelfont.realize(defaultfont_);
162 return true; // no errors
196 TC_ADDTOHTMLPREAMBLE,
207 LexerKeyword textClassTags[] = {
208 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
209 { "addtopreamble", TC_ADDTOPREAMBLE },
210 { "citeformat", TC_CITEFORMAT },
211 { "classoptions", TC_CLASSOPTIONS },
212 { "columns", TC_COLUMNS },
213 { "counter", TC_COUNTER },
214 { "defaultfont", TC_DEFAULTFONT },
215 { "defaultmodule", TC_DEFAULTMODULE },
216 { "defaultstyle", TC_DEFAULTSTYLE },
217 { "excludesmodule", TC_EXCLUDESMODULE },
218 { "float", TC_FLOAT },
219 { "format", TC_FORMAT },
220 { "htmlpreamble", TC_HTMLPREAMBLE },
221 { "htmltocsection", TC_HTMLTOCSECTION },
222 { "ifcounter", TC_IFCOUNTER },
223 { "ifstyle", TC_IFSTYLE },
224 { "input", TC_INPUT },
225 { "insetlayout", TC_INSETLAYOUT },
226 { "leftmargin", TC_LEFTMARGIN },
227 { "nofloat", TC_NOFLOAT },
228 { "nostyle", TC_NOSTYLE },
229 { "outputformat", TC_OUTPUTFORMAT },
230 { "outputtype", TC_OUTPUTTYPE },
231 { "pagestyle", TC_PAGESTYLE },
232 { "preamble", TC_PREAMBLE },
233 { "provides", TC_PROVIDES },
234 { "providesmodule", TC_PROVIDESMODULE },
235 { "requires", TC_REQUIRES },
236 { "rightmargin", TC_RIGHTMARGIN },
237 { "secnumdepth", TC_SECNUMDEPTH },
238 { "sides", TC_SIDES },
239 { "style", TC_STYLE },
240 { "titlelatexname", TC_TITLELATEXNAME },
241 { "titlelatextype", TC_TITLELATEXTYPE },
242 { "tocdepth", TC_TOCDEPTH }
248 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
250 LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
251 FileName const tempfile = FileName::tempName("convert_layout");
252 bool success = layout2layout(filename, tempfile);
254 success = readWithoutConv(tempfile, rt) == OK;
255 tempfile.removeFile();
260 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
262 if (!filename.isReadableFile()) {
263 lyxerr << "Cannot read layout file `" << filename << "'."
268 LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
269 to_utf8(makeDisplayPath(filename.absFilename())));
271 // Define the plain layout used in table cells, ert, etc. Note that
272 // we do this before loading any layout file, so that classes can
273 // override features of this layout if they should choose to do so.
274 if (rt == BASECLASS && !hasLayout(plain_layout_))
275 layoutlist_.push_back(createBasicLayout(plain_layout_));
277 Lexer lexrc(textClassTags);
278 lexrc.setFile(filename);
279 ReturnValues retval = read(lexrc, rt);
281 LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
282 to_utf8(makeDisplayPath(filename.absFilename())));
288 bool TextClass::read(FileName const & filename, ReadType rt)
290 ReturnValues const retval = readWithoutConv(filename, rt);
291 if (retval != FORMAT_MISMATCH)
294 bool const worx = convertLayoutFormat(filename, rt);
296 LYXERR0 ("Unable to convert " << filename <<
297 " to format " << FORMAT);
304 bool TextClass::validate(std::string const & str)
307 return tc.read(str, VALIDATION);
311 bool TextClass::read(std::string const & str, ReadType rt)
313 Lexer lexrc(textClassTags);
314 istringstream is(str);
316 ReturnValues retval = read(lexrc, rt);
318 if (retval != FORMAT_MISMATCH)
321 // write the layout string to a temporary file
322 FileName const tempfile = FileName::tempName("TextClass_read");
323 ofstream os(tempfile.toFilesystemEncoding().c_str());
325 LYXERR0("Unable to create temporary file");
331 // now try to convert it
332 bool const worx = convertLayoutFormat(tempfile, rt);
334 LYXERR0("Unable to convert internal layout information to format "
337 tempfile.removeFile();
342 // Reads a textclass structure from file.
343 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
345 bool error = !lexrc.isOK();
347 // Format of files before the 'Format' tag was introduced
351 while (lexrc.isOK() && !error) {
352 int le = lexrc.lex();
355 case Lexer::LEX_FEOF:
358 case Lexer::LEX_UNDEF:
359 lexrc.printError("Unknown TextClass tag `$$Token'");
367 // used below to track whether we are in an IfStyle or IfCounter tag.
368 bool ifstyle = false;
369 bool ifcounter = false;
371 switch (static_cast<TextClassTags>(le)) {
375 format = lexrc.getInteger();
378 case TC_OUTPUTFORMAT:
380 outputFormat_ = lexrc.getString();
384 readOutputType(lexrc);
385 switch(outputType_) {
387 outputFormat_ = "latex";
390 outputFormat_ = "docbook";
393 outputFormat_ = "literate";
398 case TC_INPUT: // Include file
400 string const inc = lexrc.getString();
401 FileName tmp = libFileSearch("layouts", inc,
405 lexrc.printError("Could not find input file: " + inc);
407 } else if (!read(tmp, MERGE)) {
408 lexrc.printError("Error reading input"
409 "file: " + tmp.absFilename());
415 case TC_DEFAULTSTYLE:
417 docstring const name = from_utf8(subst(lexrc.getString(),
419 defaultlayout_ = name;
428 lexrc.printError("No name given for style: `$$Token'.");
432 docstring const name = from_utf8(subst(lexrc.getString(),
435 string s = "Could not read name for style: `$$Token' "
436 + lexrc.getString() + " is probably not valid UTF-8!";
437 lexrc.printError(s.c_str());
439 // Since we couldn't read the name, we just scan the rest
440 // of the style and discard it.
441 error = !readStyle(lexrc, lay);
442 } else if (hasLayout(name)) {
443 Layout & lay = operator[](name);
444 error = !readStyle(lexrc, lay);
445 } else if (!ifstyle) {
447 layout.setName(name);
448 error = !readStyle(lexrc, layout);
450 layoutlist_.push_back(layout);
452 if (defaultlayout_.empty()) {
453 // We do not have a default layout yet, so we choose
454 // the first layout we encounter.
455 defaultlayout_ = name;
459 // scan the rest and discard it
461 readStyle(lexrc, lay);
472 docstring const style = from_utf8(subst(lexrc.getString(),
474 if (!deleteLayout(style))
475 lyxerr << "Cannot delete style `"
476 << to_utf8(style) << '\'' << endl;
482 columns_ = lexrc.getInteger();
487 switch (lexrc.getInteger()) {
488 case 1: sides_ = OneSide; break;
489 case 2: sides_ = TwoSides; break;
491 lyxerr << "Impossible number of page"
492 " sides, setting to one."
502 pagestyle_ = rtrim(lexrc.getString());
506 defaultfont_ = lyxRead(lexrc);
507 if (!defaultfont_.resolved()) {
508 lexrc.printError("Warning: defaultfont should "
509 "be fully instantiated!");
510 defaultfont_.realize(sane_font);
516 secnumdepth_ = lexrc.getInteger();
521 tocdepth_ = lexrc.getInteger();
524 // First step to support options
525 case TC_CLASSOPTIONS:
526 readClassOptions(lexrc);
530 preamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
533 case TC_HTMLPREAMBLE:
534 htmlpreamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
537 case TC_HTMLTOCSECTION:
538 html_toc_section_ = from_utf8(trim(lexrc.getString()));
541 case TC_ADDTOPREAMBLE:
542 preamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
545 case TC_ADDTOHTMLPREAMBLE:
546 htmlpreamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
551 string const feature = lexrc.getString();
553 if (lexrc.getInteger())
554 provides_.insert(feature);
556 provides_.erase(feature);
562 vector<string> const req
563 = getVectorFromString(lexrc.getString());
564 requires_.insert(req.begin(), req.end());
568 case TC_DEFAULTMODULE: {
570 string const module = lexrc.getString();
571 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
572 default_modules_.push_back(module);
576 case TC_PROVIDESMODULE: {
578 string const module = lexrc.getString();
579 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
580 provided_modules_.push_back(module);
584 case TC_EXCLUDESMODULE: {
586 string const module = lexrc.getString();
587 // modules already have their own way to exclude other modules
589 LYXERR0("ExcludesModule tag cannot be used in a module!");
592 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
593 excluded_modules_.push_back(module);
597 case TC_LEFTMARGIN: // left margin type
599 leftmargin_ = lexrc.getDocString();
602 case TC_RIGHTMARGIN: // right margin type
604 rightmargin_ = lexrc.getDocString();
607 case TC_INSETLAYOUT: {
609 lexrc.printError("No name given for InsetLayout: `$$Token'.");
613 docstring const name = subst(lexrc.getDocString(), '_', ' ');
615 string s = "Could not read name for InsetLayout: `$$Token' "
616 + lexrc.getString() + " is probably not valid UTF-8!";
617 lexrc.printError(s.c_str());
619 // Since we couldn't read the name, we just scan the rest
620 // of the style and discard it.
621 il.read(lexrc, *this);
623 } else if (hasInsetLayout(name)) {
624 InsetLayout & il = insetlayoutlist_[name];
625 error = !il.read(lexrc, *this);
629 error = !il.read(lexrc, *this);
631 insetlayoutlist_[name] = il;
641 readCiteFormat(lexrc);
648 docstring const name = lexrc.getDocString();
650 string s = "Could not read name for counter: `$$Token' "
651 + lexrc.getString() + " is probably not valid UTF-8!";
652 lexrc.printError(s.c_str());
654 // Since we couldn't read the name, we just scan the rest
658 error = !counters_.read(lexrc, name, !ifcounter);
661 lexrc.printError("No name given for style: `$$Token'.");
668 case TC_TITLELATEXTYPE:
669 readTitleType(lexrc);
672 case TC_TITLELATEXNAME:
674 titlename_ = lexrc.getString();
679 string const nofloat = lexrc.getString();
680 floatlist_.erase(nofloat);
685 //Note that this is triggered the first time through the loop unless
686 //we hit a format tag.
687 if (format != FORMAT)
691 if (format != FORMAT)
692 return FORMAT_MISMATCH;
695 return (error ? ERROR : OK);
697 if (defaultlayout_.empty()) {
698 LYXERR0("Error: Textclass '" << name_
699 << "' is missing a defaultstyle.");
703 // Try to erase "stdinsets" from the provides_ set.
705 // Provides stdinsets 1
706 // declaration simply tells us that the standard insets have been
707 // defined. (It's found in stdinsets.inc but could also be used in
708 // user-defined files.) There isn't really any such package. So we
709 // might as well go ahead and erase it.
710 // If we do not succeed, then it was not there, which means that
711 // the textclass did not provide the definitions of the standard
712 // insets. So we need to try to load them.
713 int erased = provides_.erase("stdinsets");
715 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
718 throw ExceptionMessage(WarningException, _("Missing File"),
719 _("Could not find stdinsets.inc! This may lead to data loss!"));
721 } else if (!read(tmp, MERGE)) {
722 throw ExceptionMessage(WarningException, _("Corrupt File"),
723 _("Could not read stdinsets.inc! This may lead to data loss!"));
728 min_toclevel_ = Layout::NOT_IN_TOC;
729 max_toclevel_ = Layout::NOT_IN_TOC;
730 const_iterator lit = begin();
731 const_iterator len = end();
732 for (; lit != len; ++lit) {
733 int const toclevel = lit->toclevel;
734 if (toclevel != Layout::NOT_IN_TOC) {
735 if (min_toclevel_ == Layout::NOT_IN_TOC)
736 min_toclevel_ = toclevel;
738 min_toclevel_ = min(min_toclevel_, toclevel);
739 max_toclevel_ = max(max_toclevel_, toclevel);
742 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
743 << ", maximum is " << max_toclevel_);
745 return (error ? ERROR : OK);
749 void TextClass::readTitleType(Lexer & lexrc)
751 LexerKeyword titleTypeTags[] = {
752 { "commandafter", TITLE_COMMAND_AFTER },
753 { "environment", TITLE_ENVIRONMENT }
756 PushPopHelper pph(lexrc, titleTypeTags);
758 int le = lexrc.lex();
760 case Lexer::LEX_UNDEF:
761 lexrc.printError("Unknown output type `$$Token'");
763 case TITLE_COMMAND_AFTER:
764 case TITLE_ENVIRONMENT:
765 titletype_ = static_cast<TitleLatexType>(le);
768 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
774 void TextClass::readOutputType(Lexer & lexrc)
776 LexerKeyword outputTypeTags[] = {
777 { "docbook", DOCBOOK },
779 { "literate", LITERATE }
782 PushPopHelper pph(lexrc, outputTypeTags);
784 int le = lexrc.lex();
786 case Lexer::LEX_UNDEF:
787 lexrc.printError("Unknown output type `$$Token'");
792 outputType_ = static_cast<OutputType>(le);
795 LYXERR0("Unhandled value " << le);
801 void TextClass::readClassOptions(Lexer & lexrc)
811 LexerKeyword classOptionsTags[] = {
813 {"fontsize", CO_FONTSIZE },
814 {"header", CO_HEADER },
815 {"other", CO_OTHER },
816 {"pagestyle", CO_PAGESTYLE }
819 lexrc.pushTable(classOptionsTags);
821 while (!getout && lexrc.isOK()) {
822 int le = lexrc.lex();
824 case Lexer::LEX_UNDEF:
825 lexrc.printError("Unknown ClassOption tag `$$Token'");
832 opt_fontsize_ = rtrim(lexrc.getString());
836 opt_pagestyle_ = rtrim(lexrc.getString());
840 options_ = lexrc.getString();
844 class_header_ = subst(lexrc.getString(), """, "\"");
855 void TextClass::readCiteFormat(Lexer & lexrc)
859 while (lexrc.isOK()) {
861 etype = lexrc.getString();
862 if (!lexrc.isOK() || compare_ascii_no_case(etype, "end") == 0)
865 definition = lexrc.getString();
866 cite_formats_[etype] = definition;
871 void TextClass::readFloat(Lexer & lexrc)
890 LexerKeyword floatTags[] = {
892 { "extension", FT_EXT },
893 { "guiname", FT_NAME },
894 { "htmlattr", FT_HTMLATTR },
895 { "htmlstyle", FT_HTMLSTYLE },
896 { "htmltag", FT_HTMLTAG },
897 { "listcommand", FT_LISTCOMMAND },
898 { "listname", FT_LISTNAME },
899 { "needsfloatpkg", FT_NEEDSFLOAT },
900 { "numberwithin", FT_WITHIN },
901 { "placement", FT_PLACEMENT },
902 { "refprefix", FT_REFPREFIX },
903 { "style", FT_STYLE },
907 lexrc.pushTable(floatTags);
921 bool needsfloat = true;
924 while (!getout && lexrc.isOK()) {
925 int le = lexrc.lex();
927 case Lexer::LEX_UNDEF:
928 lexrc.printError("Unknown float tag `$$Token'");
935 type = lexrc.getString();
936 if (floatlist_.typeExist(type)) {
937 Floating const & fl = floatlist_.getType(type);
938 placement = fl.placement();
940 within = fl.within();
943 listname = fl.listName();
944 needsfloat = fl.needsFloatPkg();
945 listcommand = fl.listCommand();
946 refprefix = fl.refPrefix();
951 name = lexrc.getString();
955 placement = lexrc.getString();
959 ext = lexrc.getString();
963 within = lexrc.getString();
964 if (within == "none")
969 style = lexrc.getString();
973 listcommand = lexrc.getString();
977 refprefix = lexrc.getString();
981 listname = lexrc.getString();
985 needsfloat = lexrc.getBool();
989 htmlattr = lexrc.getString();
993 htmlstyle = lexrc.getLongString("EndHTMLStyle");
997 htmltag = lexrc.getString();
1005 // Here we have a full float if getout == true
1007 if (!needsfloat && listcommand.empty())
1008 LYXERR0("The layout does not provide a list command " <<
1009 "for the builtin float `" << type << "'. LyX will " <<
1010 "not be able to produce a float list.");
1011 Floating fl(type, placement, ext, within, style, name,
1012 listname, listcommand, refprefix,
1013 htmltag, htmlattr, htmlstyle, needsfloat);
1014 floatlist_.newFloat(fl);
1015 // each float has its own counter
1016 counters_.newCounter(from_ascii(type), from_ascii(within),
1017 docstring(), docstring());
1018 // also define sub-float counters
1019 docstring const subtype = "sub-" + from_ascii(type);
1020 counters_.newCounter(subtype, from_ascii(type),
1021 "\\alph{" + subtype + "}", docstring());
1028 string const & TextClass::prerequisites() const
1030 if (contains(prerequisites_, ',')) {
1031 vector<string> const pres = getVectorFromString(prerequisites_);
1032 prerequisites_ = getStringFromVector(pres, "\n\t");
1034 return prerequisites_;
1037 bool TextClass::hasLayout(docstring const & n) const
1039 docstring const name = n.empty() ? defaultLayoutName() : n;
1041 return find_if(layoutlist_.begin(), layoutlist_.end(),
1042 LayoutNamesEqual(name))
1043 != layoutlist_.end();
1047 bool TextClass::hasInsetLayout(docstring const & n) const
1051 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
1052 InsetLayouts::const_iterator en = insetlayoutlist_.end();
1053 for (; it != en; ++it)
1060 Layout const & TextClass::operator[](docstring const & name) const
1062 LASSERT(!name.empty(), /**/);
1065 find_if(begin(), end(), LayoutNamesEqual(name));
1068 lyxerr << "We failed to find the layout '" << to_utf8(name)
1069 << "' in the layout list. You MUST investigate!"
1071 for (const_iterator cit = begin(); cit != end(); ++cit)
1072 lyxerr << " " << to_utf8(cit->name()) << endl;
1074 // we require the name to exist
1075 LASSERT(false, /**/);
1082 Layout & TextClass::operator[](docstring const & name)
1084 LASSERT(!name.empty(), /**/);
1086 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1089 LYXERR0("We failed to find the layout '" << to_utf8(name)
1090 << "' in the layout list. You MUST investigate!");
1091 for (const_iterator cit = begin(); cit != end(); ++cit)
1092 LYXERR0(" " << to_utf8(cit->name()));
1094 // we require the name to exist
1095 LASSERT(false, /**/);
1102 bool TextClass::deleteLayout(docstring const & name)
1104 if (name == defaultLayoutName() || name == plainLayoutName())
1107 LayoutList::iterator it =
1108 remove_if(layoutlist_.begin(), layoutlist_.end(),
1109 LayoutNamesEqual(name));
1111 LayoutList::iterator end = layoutlist_.end();
1112 bool const ret = (it != end);
1113 layoutlist_.erase(it, end);
1118 // Load textclass info if not loaded yet
1119 bool TextClass::load(string const & path) const
1124 // Read style-file, provided path is searched before the system ones
1125 // If path is a file, it is loaded directly.
1126 FileName layout_file(path);
1127 if (!path.empty() && !layout_file.isReadableFile())
1128 layout_file = FileName(addName(path, name_ + ".layout"));
1129 if (layout_file.empty() || !layout_file.exists())
1130 layout_file = libFileSearch("layouts", name_, "layout");
1131 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1134 lyxerr << "Error reading `"
1135 << to_utf8(makeDisplayPath(layout_file.absFilename()))
1136 << "'\n(Check `" << name_
1137 << "')\nCheck your installation and "
1138 "try Options/Reconfigure..." << endl;
1145 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1148 layoutlist_.push_back(createBasicLayout(n, true));
1152 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1154 // FIXME The fix for the InsetLayout part of 4812 would be here:
1155 // Add the InsetLayout to the document class if it is not found.
1157 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1158 while (!n.empty()) {
1159 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1160 if (cit != cen && cit->first == n)
1162 size_t i = n.find(':');
1163 if (i == string::npos)
1167 return plain_insetlayout_;
1171 docstring const & TextClass::defaultLayoutName() const
1173 // This really should come from the actual layout... (Lgb)
1174 return defaultlayout_;
1178 Layout const & TextClass::defaultLayout() const
1180 return operator[](defaultLayoutName());
1184 bool TextClass::isDefaultLayout(Layout const & layout) const
1186 return layout.name() == defaultLayoutName();
1190 bool TextClass::isPlainLayout(Layout const & layout) const
1192 return layout.name() == plainLayoutName();
1196 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1198 static Layout * defaultLayout = NULL;
1200 if (defaultLayout) {
1201 defaultLayout->setUnknown(unknown);
1202 defaultLayout->setName(name);
1203 return *defaultLayout;
1206 static char const * s = "Margin Static\n"
1207 "LatexType Paragraph\n"
1210 "AlignPossible Left, Right, Center\n"
1211 "LabelType No_Label\n"
1213 istringstream ss(s);
1214 Lexer lex(textClassTags);
1216 defaultLayout = new Layout;
1217 defaultLayout->setUnknown(unknown);
1218 defaultLayout->setName(name);
1219 if (!readStyle(lex, *defaultLayout)) {
1220 // The only way this happens is because the hardcoded layout above
1222 LASSERT(false, /**/);
1224 return *defaultLayout;
1228 /////////////////////////////////////////////////////////////////////////
1230 // DocumentClassBundle
1232 /////////////////////////////////////////////////////////////////////////
1234 DocumentClassBundle::~DocumentClassBundle()
1236 for (size_t i = 0; i != documentClasses_.size(); ++i)
1237 delete documentClasses_[i];
1238 documentClasses_.clear();
1241 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1243 DocumentClass * dc = new DocumentClass(baseClass);
1244 documentClasses_.push_back(dc);
1245 return *documentClasses_.back();
1249 DocumentClassBundle & DocumentClassBundle::get()
1251 static DocumentClassBundle singleton;
1256 DocumentClass & DocumentClassBundle::makeDocumentClass(
1257 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1259 DocumentClass & doc_class = newClass(baseClass);
1260 LayoutModuleList::const_iterator it = modlist.begin();
1261 LayoutModuleList::const_iterator en = modlist.end();
1262 for (; it != en; it++) {
1263 string const modName = *it;
1264 LyXModule * lm = theModuleList[modName];
1266 docstring const msg =
1267 bformat(_("The module %1$s has been requested by\n"
1268 "this document but has not been found in the list of\n"
1269 "available modules. If you recently installed it, you\n"
1270 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1271 ExceptionMessage(WarningException,_("Module not available"),
1272 msg + _("Some layouts may not be available."));
1275 if (!lm->isAvailable()) {
1276 docstring const msg =
1277 bformat(_("The module %1$s requires a package that is\n"
1278 "not available in your LaTeX installation. LaTeX output\n"
1279 "may not be possible.\n"), from_utf8(modName));
1280 ExceptionMessage(WarningException, _("Package not available"), msg);
1282 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1283 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1284 docstring const msg =
1285 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1286 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1293 /////////////////////////////////////////////////////////////////////////
1297 /////////////////////////////////////////////////////////////////////////
1299 DocumentClass::DocumentClass(LayoutFile const & tc)
1304 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1306 LayoutList::const_iterator it = layoutlist_.begin();
1307 LayoutList::const_iterator end = layoutlist_.end();
1308 for (; it != end; ++it)
1309 if (it->latexname() == lay)
1315 bool DocumentClass::provides(string const & p) const
1317 return provides_.find(p) != provides_.end();
1321 bool DocumentClass::hasTocLevels() const
1323 return min_toclevel_ != Layout::NOT_IN_TOC;
1327 Layout const & DocumentClass::htmlTOCLayout() const
1329 if (html_toc_section_.empty()) {
1330 // we're going to look for the layout with the minimum toclevel
1331 TextClass::LayoutList::const_iterator lit = begin();
1332 TextClass::LayoutList::const_iterator const len = end();
1333 int minlevel = 1000;
1334 Layout const * lay = NULL;
1335 for (; lit != len; ++lit) {
1336 int const level = lit->toclevel;
1337 // we don't want Part
1338 if (level == Layout::NOT_IN_TOC || level < 0 || level >= minlevel)
1344 html_toc_section_ = lay->name();
1346 // hmm. that is very odd, so we'll do our best
1347 html_toc_section_ = defaultLayoutName();
1349 return operator[](html_toc_section_);
1353 string const & DocumentClass::getCiteFormat(string const & entry_type) const
1355 static string default_format = "{%author%[[%author%, ]][[{%editor%[[%editor%, %ed_text%, ]]}]]}\"%title%\"{%journal%[[, {!<i>!}%journal%{!</i>!}]][[{%publisher%[[, %publisher%]][[{%institution%[[, %institution%]]}]]}]]}{%year%[[ (%year%)]]}{%pages%[[, %pages%]]}.";
1357 map<string, string>::const_iterator it = cite_formats_.find(entry_type);
1358 if (it != cite_formats_.end())
1360 return default_format;
1364 /////////////////////////////////////////////////////////////////////////
1368 /////////////////////////////////////////////////////////////////////////
1370 ostream & operator<<(ostream & os, PageSides p)