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"
45 using namespace lyx::support;
51 class LayoutNamesEqual : public unary_function<Layout, bool> {
53 LayoutNamesEqual(docstring const & name)
56 bool operator()(Layout const & c) const
58 return c.name() == name_;
64 // Keep the changes documented in the Customization manual.
65 int const FORMAT = 14;
68 bool layout2layout(FileName const & filename, FileName const & tempfile)
70 FileName const script = libFileSearch("scripts", "layout2layout.py");
72 LYXERR0("Could not find layout conversion "
73 "script layout2layout.py.");
77 ostringstream command;
78 command << os::python() << ' ' << quoteName(script.toFilesystemEncoding())
79 << ' ' << quoteName(filename.toFilesystemEncoding())
80 << ' ' << quoteName(tempfile.toFilesystemEncoding());
81 string const command_str = command.str();
83 LYXERR(Debug::TCLASS, "Running `" << command_str << '\'');
85 cmd_ret const ret = runCommand(command_str);
87 LYXERR0("Could not run layout conversion script layout2layout.py.");
94 std::string translateRT(TextClass::ReadType rt)
97 case TextClass::BASECLASS:
99 case TextClass::MERGE:
101 case TextClass::MODULE:
102 return "module file";
103 case TextClass::VALIDATION:
113 // This string should not be translated here,
114 // because it is a layout identifier.
115 docstring const TextClass::plain_layout_ = from_ascii("Plain Layout");
118 InsetLayout DocumentClass::plain_insetlayout_;
121 /////////////////////////////////////////////////////////////////////////
125 /////////////////////////////////////////////////////////////////////////
127 TextClass::TextClass()
134 pagestyle_ = "default";
135 defaultfont_ = sane_font;
136 opt_fontsize_ = "10|11|12";
137 opt_pagestyle_ = "empty|plain|headings|fancy";
138 titletype_ = TITLE_COMMAND_AFTER;
139 titlename_ = "maketitle";
141 _("Plain Layout"); // a hack to make this translatable
145 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
147 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
148 if (!lay.read(lexrc, *this)) {
149 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
153 lay.resfont = lay.font;
154 lay.resfont.realize(defaultfont_);
155 lay.reslabelfont = lay.labelfont;
156 lay.reslabelfont.realize(defaultfont_);
157 return true; // no errors
195 LexerKeyword textClassTags[] = {
196 { "addtopreamble", TC_ADDTOPREAMBLE },
197 { "classoptions", TC_CLASSOPTIONS },
198 { "columns", TC_COLUMNS },
199 { "counter", TC_COUNTER },
200 { "defaultfont", TC_DEFAULTFONT },
201 { "defaultmodule", TC_DEFAULTMODULE },
202 { "defaultstyle", TC_DEFAULTSTYLE },
203 { "excludesmodule", TC_EXCLUDESMODULE },
204 { "float", TC_FLOAT },
205 { "format", TC_FORMAT },
206 { "input", TC_INPUT },
207 { "insetlayout", TC_INSETLAYOUT },
208 { "leftmargin", TC_LEFTMARGIN },
209 { "nofloat", TC_NOFLOAT },
210 { "nostyle", TC_NOSTYLE },
211 { "outputtype", TC_OUTPUTTYPE },
212 { "pagestyle", TC_PAGESTYLE },
213 { "preamble", TC_PREAMBLE },
214 { "provides", TC_PROVIDES },
215 { "providesmodule", TC_PROVIDESMODULE },
216 { "requires", TC_REQUIRES },
217 { "rightmargin", TC_RIGHTMARGIN },
218 { "secnumdepth", TC_SECNUMDEPTH },
219 { "sides", TC_SIDES },
220 { "style", TC_STYLE },
221 { "titlelatexname", TC_TITLELATEXNAME },
222 { "titlelatextype", TC_TITLELATEXTYPE },
223 { "tocdepth", TC_TOCDEPTH }
229 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
231 LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
232 FileName const tempfile = FileName::tempName("convert_layout");
233 bool success = layout2layout(filename, tempfile);
235 success = readWithoutConv(tempfile, rt) == OK;
236 tempfile.removeFile();
241 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
243 if (!filename.isReadableFile()) {
244 lyxerr << "Cannot read layout file `" << filename << "'."
249 LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
250 to_utf8(makeDisplayPath(filename.absFilename())));
252 // Define the plain layout used in table cells, ert, etc. Note that
253 // we do this before loading any layout file, so that classes can
254 // override features of this layout if they should choose to do so.
255 if (rt == BASECLASS && !hasLayout(plain_layout_))
256 layoutlist_.push_back(createBasicLayout(plain_layout_));
258 Lexer lexrc(textClassTags);
259 lexrc.setFile(filename);
260 ReturnValues retval = read(lexrc, rt);
262 LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
263 to_utf8(makeDisplayPath(filename.absFilename())));
269 bool TextClass::read(FileName const & filename, ReadType rt)
271 ReturnValues const retval = readWithoutConv(filename, rt);
272 if (retval != FORMAT_MISMATCH)
275 bool const worx = convertLayoutFormat(filename, rt);
277 LYXERR0 ("Unable to convert " << filename <<
278 " to format " << FORMAT);
285 bool TextClass::validate(std::string const & str)
288 return tc.read(str, VALIDATION);
292 bool TextClass::read(std::string const & str, ReadType rt)
294 Lexer lexrc(textClassTags);
295 istringstream is(str);
297 ReturnValues retval = read(lexrc, rt);
299 if (retval != FORMAT_MISMATCH)
302 // write the layout string to a temporary file
303 FileName const tempfile = FileName::tempName("TextClass_read");
304 ofstream os(tempfile.toFilesystemEncoding().c_str());
306 LYXERR0("Unable to create temporary file");
312 // now try to convert it
313 bool const worx = convertLayoutFormat(tempfile, rt);
315 LYXERR0("Unable to convert internal layout information to format "
318 tempfile.removeFile();
323 // Reads a textclass structure from file.
324 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
326 bool error = !lexrc.isOK();
328 // Format of files before the 'Format' tag was introduced
332 while (lexrc.isOK() && !error) {
333 int le = lexrc.lex();
336 case Lexer::LEX_FEOF:
339 case Lexer::LEX_UNDEF:
340 lexrc.printError("Unknown TextClass tag `$$Token'");
348 switch (static_cast<TextClassTags>(le)) {
352 format = lexrc.getInteger();
355 case TC_OUTPUTTYPE: // output type definition
356 readOutputType(lexrc);
359 case TC_INPUT: // Include file
361 string const inc = lexrc.getString();
362 FileName tmp = libFileSearch("layouts", inc,
366 lexrc.printError("Could not find input file: " + inc);
368 } else if (!read(tmp, MERGE)) {
369 lexrc.printError("Error reading input"
370 "file: " + tmp.absFilename());
376 case TC_DEFAULTSTYLE:
378 docstring const name = from_utf8(subst(lexrc.getString(),
380 defaultlayout_ = name;
386 lexrc.printError("No name given for style: `$$Token'.");
390 docstring const name = from_utf8(subst(lexrc.getString(),
393 string s = "Could not read name for style: `$$Token' "
394 + lexrc.getString() + " is probably not valid UTF-8!";
395 lexrc.printError(s.c_str());
397 // Since we couldn't read the name, we just scan the rest
398 // of the style and discard it.
399 error = !readStyle(lexrc, lay);
400 } else if (hasLayout(name)) {
401 Layout & lay = operator[](name);
402 error = !readStyle(lexrc, lay);
405 layout.setName(name);
406 error = !readStyle(lexrc, layout);
408 layoutlist_.push_back(layout);
410 if (defaultlayout_.empty()) {
411 // We do not have a default layout yet, so we choose
412 // the first layout we encounter.
413 defaultlayout_ = name;
421 docstring const style = from_utf8(subst(lexrc.getString(),
423 if (!deleteLayout(style))
424 lyxerr << "Cannot delete style `"
425 << to_utf8(style) << '\'' << endl;
431 columns_ = lexrc.getInteger();
436 switch (lexrc.getInteger()) {
437 case 1: sides_ = OneSide; break;
438 case 2: sides_ = TwoSides; break;
440 lyxerr << "Impossible number of page"
441 " sides, setting to one."
451 pagestyle_ = rtrim(lexrc.getString());
455 defaultfont_ = lyxRead(lexrc);
456 if (!defaultfont_.resolved()) {
457 lexrc.printError("Warning: defaultfont should "
458 "be fully instantiated!");
459 defaultfont_.realize(sane_font);
465 secnumdepth_ = lexrc.getInteger();
470 tocdepth_ = lexrc.getInteger();
473 // First step to support options
474 case TC_CLASSOPTIONS:
475 readClassOptions(lexrc);
479 preamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
482 case TC_ADDTOPREAMBLE:
483 preamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
488 string const feature = lexrc.getString();
490 if (lexrc.getInteger())
491 provides_.insert(feature);
493 provides_.erase(feature);
499 vector<string> const req
500 = getVectorFromString(lexrc.getString());
501 requires_.insert(req.begin(), req.end());
505 case TC_DEFAULTMODULE: {
507 string const module = lexrc.getString();
508 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
509 default_modules_.push_back(module);
513 case TC_PROVIDESMODULE: {
515 string const module = lexrc.getString();
516 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
517 provided_modules_.push_back(module);
521 case TC_EXCLUDESMODULE: {
523 string const module = lexrc.getString();
524 // modules already have their own way to exclude other modules
526 LYXERR0("ExcludesModule tag cannot be used in a module!");
529 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
530 excluded_modules_.push_back(module);
534 case TC_LEFTMARGIN: // left margin type
536 leftmargin_ = lexrc.getDocString();
539 case TC_RIGHTMARGIN: // right margin type
541 rightmargin_ = lexrc.getDocString();
544 case TC_INSETLAYOUT: {
546 lexrc.printError("No name given for InsetLayout: `$$Token'.");
550 docstring const name = subst(lexrc.getDocString(), '_', ' ');
552 string s = "Could not read name for InsetLayout: `$$Token' "
553 + lexrc.getString() + " is probably not valid UTF-8!";
554 lexrc.printError(s.c_str());
556 // Since we couldn't read the name, we just scan the rest
557 // of the style and discard it.
558 il.read(lexrc, *this);
560 } else if (hasInsetLayout(name)) {
561 InsetLayout & il = insetlayoutlist_[name];
562 error = !il.read(lexrc, *this);
566 error = !il.read(lexrc, *this);
568 insetlayoutlist_[name] = il;
579 docstring const name = lexrc.getDocString();
581 string s = "Could not read name for counter: `$$Token' "
582 + lexrc.getString() + " is probably not valid UTF-8!";
583 lexrc.printError(s.c_str());
585 // Since we couldn't read the name, we just scan the rest
589 error = !counters_.read(lexrc, name);
592 lexrc.printError("No name given for style: `$$Token'.");
597 case TC_TITLELATEXTYPE:
598 readTitleType(lexrc);
601 case TC_TITLELATEXNAME:
603 titlename_ = lexrc.getString();
608 string const nofloat = lexrc.getString();
609 floatlist_.erase(nofloat);
614 //Note that this is triggered the first time through the loop unless
615 //we hit a format tag.
616 if (format != FORMAT)
620 if (format != FORMAT)
621 return FORMAT_MISMATCH;
624 return (error ? ERROR : OK);
626 if (defaultlayout_.empty()) {
627 LYXERR0("Error: Textclass '" << name_
628 << "' is missing a defaultstyle.");
632 // Try to erase "stdinsets" from the provides_ set.
634 // Provides stdinsets 1
635 // declaration simply tells us that the standard insets have been
636 // defined. (It's found in stdinsets.inc but could also be used in
637 // user-defined files.) There isn't really any such package. So we
638 // might as well go ahead and erase it.
639 // If we do not succeed, then it was not there, which means that
640 // the textclass did not provide the definitions of the standard
641 // insets. So we need to try to load them.
642 int erased = provides_.erase("stdinsets");
644 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
647 throw ExceptionMessage(WarningException, _("Missing File"),
648 _("Could not find stdinsets.inc! This may lead to data loss!"));
650 } else if (!read(tmp, MERGE)) {
651 throw ExceptionMessage(WarningException, _("Corrupt File"),
652 _("Could not read stdinsets.inc! This may lead to data loss!"));
657 min_toclevel_ = Layout::NOT_IN_TOC;
658 max_toclevel_ = Layout::NOT_IN_TOC;
659 const_iterator lit = begin();
660 const_iterator len = end();
661 for (; lit != len; ++lit) {
662 int const toclevel = lit->toclevel;
663 if (toclevel != Layout::NOT_IN_TOC) {
664 if (min_toclevel_ == Layout::NOT_IN_TOC)
665 min_toclevel_ = toclevel;
667 min_toclevel_ = min(min_toclevel_, toclevel);
668 max_toclevel_ = max(max_toclevel_, toclevel);
671 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
672 << ", maximum is " << max_toclevel_);
674 return (error ? ERROR : OK);
678 void TextClass::readTitleType(Lexer & lexrc)
680 LexerKeyword titleTypeTags[] = {
681 { "commandafter", TITLE_COMMAND_AFTER },
682 { "environment", TITLE_ENVIRONMENT }
685 PushPopHelper pph(lexrc, titleTypeTags);
687 int le = lexrc.lex();
689 case Lexer::LEX_UNDEF:
690 lexrc.printError("Unknown output type `$$Token'");
692 case TITLE_COMMAND_AFTER:
693 case TITLE_ENVIRONMENT:
694 titletype_ = static_cast<TitleLatexType>(le);
697 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
703 void TextClass::readOutputType(Lexer & lexrc)
705 LexerKeyword outputTypeTags[] = {
706 { "docbook", DOCBOOK },
708 { "literate", LITERATE }
711 PushPopHelper pph(lexrc, outputTypeTags);
713 int le = lexrc.lex();
715 case Lexer::LEX_UNDEF:
716 lexrc.printError("Unknown output type `$$Token'");
721 outputType_ = static_cast<OutputType>(le);
724 LYXERR0("Unhandled value " << le);
730 void TextClass::readClassOptions(Lexer & lexrc)
740 LexerKeyword classOptionsTags[] = {
742 {"fontsize", CO_FONTSIZE },
743 {"header", CO_HEADER },
744 {"other", CO_OTHER },
745 {"pagestyle", CO_PAGESTYLE }
748 lexrc.pushTable(classOptionsTags);
750 while (!getout && lexrc.isOK()) {
751 int le = lexrc.lex();
753 case Lexer::LEX_UNDEF:
754 lexrc.printError("Unknown ClassOption tag `$$Token'");
761 opt_fontsize_ = rtrim(lexrc.getString());
765 opt_pagestyle_ = rtrim(lexrc.getString());
769 options_ = lexrc.getString();
773 class_header_ = subst(lexrc.getString(), """, "\"");
784 void TextClass::readFloat(Lexer & lexrc)
798 LexerKeyword floatTags[] = {
800 { "extension", FT_EXT },
801 { "guiname", FT_NAME },
802 { "latexbuiltin", FT_BUILTIN },
803 { "listname", FT_LISTNAME },
804 { "numberwithin", FT_WITHIN },
805 { "placement", FT_PLACEMENT },
806 { "style", FT_STYLE },
810 lexrc.pushTable(floatTags);
819 bool builtin = false;
822 while (!getout && lexrc.isOK()) {
823 int le = lexrc.lex();
825 case Lexer::LEX_UNDEF:
826 lexrc.printError("Unknown float tag `$$Token'");
833 type = lexrc.getString();
834 if (floatlist_.typeExist(type)) {
835 Floating const & fl = floatlist_.getType(type);
836 placement = fl.placement();
838 within = fl.within();
841 listName = fl.listName();
842 builtin = fl.builtin();
847 name = lexrc.getString();
851 placement = lexrc.getString();
855 ext = lexrc.getString();
859 within = lexrc.getString();
860 if (within == "none")
865 style = lexrc.getString();
869 listName = lexrc.getString();
873 builtin = lexrc.getBool();
881 // Here if have a full float if getout == true
883 Floating fl(type, placement, ext, within,
884 style, name, listName, builtin);
885 floatlist_.newFloat(fl);
886 // each float has its own counter
887 counters_.newCounter(from_ascii(type), from_ascii(within),
888 docstring(), docstring());
889 // also define sub-float counters
890 docstring const subtype = "sub-" + from_ascii(type);
891 counters_.newCounter(subtype, from_ascii(type),
892 "\\alph{" + subtype + "}", docstring());
899 bool TextClass::hasLayout(docstring const & n) const
901 docstring const name = n.empty() ? defaultLayoutName() : n;
903 return find_if(layoutlist_.begin(), layoutlist_.end(),
904 LayoutNamesEqual(name))
905 != layoutlist_.end();
909 bool TextClass::hasInsetLayout(docstring const & n) const
913 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
914 InsetLayouts::const_iterator en = insetlayoutlist_.end();
915 for (; it != en; ++it)
922 Layout const & TextClass::operator[](docstring const & name) const
924 LASSERT(!name.empty(), /**/);
927 find_if(begin(), end(), LayoutNamesEqual(name));
930 lyxerr << "We failed to find the layout '" << to_utf8(name)
931 << "' in the layout list. You MUST investigate!"
933 for (const_iterator cit = begin(); cit != end(); ++cit)
934 lyxerr << " " << to_utf8(cit->name()) << endl;
936 // we require the name to exist
937 LASSERT(false, /**/);
944 Layout & TextClass::operator[](docstring const & name)
946 LASSERT(!name.empty(), /**/);
948 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
951 LYXERR0("We failed to find the layout '" << to_utf8(name)
952 << "' in the layout list. You MUST investigate!");
953 for (const_iterator cit = begin(); cit != end(); ++cit)
954 LYXERR0(" " << to_utf8(cit->name()));
956 // we require the name to exist
957 LASSERT(false, /**/);
964 bool TextClass::deleteLayout(docstring const & name)
966 if (name == defaultLayoutName() || name == plainLayoutName())
969 LayoutList::iterator it =
970 remove_if(layoutlist_.begin(), layoutlist_.end(),
971 LayoutNamesEqual(name));
973 LayoutList::iterator end = layoutlist_.end();
974 bool const ret = (it != end);
975 layoutlist_.erase(it, end);
980 // Load textclass info if not loaded yet
981 bool TextClass::load(string const & path) const
986 // Read style-file, provided path is searched before the system ones
987 // If path is a file, it is loaded directly.
988 FileName layout_file(path);
989 if (!path.empty() && !layout_file.isReadableFile())
990 layout_file = FileName(addName(path, name_ + ".layout"));
991 if (layout_file.empty() || !layout_file.exists())
992 layout_file = libFileSearch("layouts", name_, "layout");
993 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
996 lyxerr << "Error reading `"
997 << to_utf8(makeDisplayPath(layout_file.absFilename()))
998 << "'\n(Check `" << name_
999 << "')\nCheck your installation and "
1000 "try Options/Reconfigure..." << endl;
1007 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1010 layoutlist_.push_back(createBasicLayout(n, true));
1014 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1016 // FIXME The fix for the InsetLayout part of 4812 would be here:
1017 // Add the InsetLayout to the document class if it is not found.
1019 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1020 while (!n.empty()) {
1021 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1022 if (cit != cen && cit->first == n)
1024 size_t i = n.find(':');
1025 if (i == string::npos)
1029 return plain_insetlayout_;
1033 docstring const & TextClass::defaultLayoutName() const
1035 // This really should come from the actual layout... (Lgb)
1036 return defaultlayout_;
1040 Layout const & TextClass::defaultLayout() const
1042 return operator[](defaultLayoutName());
1046 bool TextClass::isDefaultLayout(Layout const & layout) const
1048 return layout.name() == defaultLayoutName();
1052 bool TextClass::isPlainLayout(Layout const & layout) const
1054 return layout.name() == plainLayoutName();
1058 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1060 static Layout * defaultLayout = NULL;
1062 if (defaultLayout) {
1063 defaultLayout->setUnknown(unknown);
1064 defaultLayout->setName(name);
1065 return *defaultLayout;
1068 static char const * s = "Margin Static\n"
1069 "LatexType Paragraph\n"
1072 "AlignPossible Left, Right, Center\n"
1073 "LabelType No_Label\n"
1075 istringstream ss(s);
1076 Lexer lex(textClassTags);
1078 defaultLayout = new Layout;
1079 defaultLayout->setUnknown(unknown);
1080 defaultLayout->setName(name);
1081 if (!readStyle(lex, *defaultLayout)) {
1082 // The only way this happens is because the hardcoded layout above
1084 LASSERT(false, /**/);
1086 return *defaultLayout;
1089 /////////////////////////////////////////////////////////////////////////
1091 // DocumentClassBundle
1093 /////////////////////////////////////////////////////////////////////////
1095 DocumentClassBundle::~DocumentClassBundle()
1097 for (size_t i = 0; i != documentClasses_.size(); ++i)
1098 delete documentClasses_[i];
1099 documentClasses_.clear();
1102 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1104 DocumentClass * dc = new DocumentClass(baseClass);
1105 documentClasses_.push_back(dc);
1106 return *documentClasses_.back();
1110 DocumentClassBundle & DocumentClassBundle::get()
1112 static DocumentClassBundle singleton;
1117 DocumentClass & DocumentClassBundle::makeDocumentClass(
1118 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1120 DocumentClass & doc_class = newClass(baseClass);
1121 LayoutModuleList::const_iterator it = modlist.begin();
1122 LayoutModuleList::const_iterator en = modlist.end();
1123 for (; it != en; it++) {
1124 string const modName = *it;
1125 LyXModule * lm = moduleList[modName];
1127 docstring const msg =
1128 bformat(_("The module %1$s has been requested by\n"
1129 "this document but has not been found in the list of\n"
1130 "available modules. If you recently installed it, you\n"
1131 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1132 ExceptionMessage(WarningException,_("Module not available"),
1133 msg + _("Some layouts may not be available."));
1136 if (!lm->isAvailable()) {
1137 docstring const msg =
1138 bformat(_("The module %1$s requires a package that is\n"
1139 "not available in your LaTeX installation. LaTeX output\n"
1140 "may not be possible.\n"), from_utf8(modName));
1141 ExceptionMessage(WarningException, _("Package not available"), msg);
1143 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1144 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1145 docstring const msg =
1146 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1147 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1154 /////////////////////////////////////////////////////////////////////////
1158 /////////////////////////////////////////////////////////////////////////
1160 DocumentClass::DocumentClass(LayoutFile const & tc)
1165 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1167 LayoutList::const_iterator it = layoutlist_.begin();
1168 LayoutList::const_iterator end = layoutlist_.end();
1169 for (; it != end; ++it)
1170 if (it->latexname() == lay)
1176 bool DocumentClass::provides(string const & p) const
1178 return provides_.find(p) != provides_.end();
1182 bool DocumentClass::hasTocLevels() const
1184 return min_toclevel_ != Layout::NOT_IN_TOC;
1188 /////////////////////////////////////////////////////////////////////////
1192 /////////////////////////////////////////////////////////////////////////
1194 ostream & operator<<(ostream & os, PageSides p)