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 = 16;
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()
130 outputFormat_ = "latex";
135 pagestyle_ = "default";
136 defaultfont_ = sane_font;
137 opt_fontsize_ = "10|11|12";
138 opt_pagestyle_ = "empty|plain|headings|fancy";
139 titletype_ = TITLE_COMMAND_AFTER;
140 titlename_ = "maketitle";
142 _("Plain Layout"); // a hack to make this translatable
146 bool TextClass::readStyle(Lexer & lexrc, Layout & lay) const
148 LYXERR(Debug::TCLASS, "Reading style " << to_utf8(lay.name()));
149 if (!lay.read(lexrc, *this)) {
150 LYXERR0("Error parsing style `" << to_utf8(lay.name()) << '\'');
154 lay.resfont = lay.font;
155 lay.resfont.realize(defaultfont_);
156 lay.reslabelfont = lay.labelfont;
157 lay.reslabelfont.realize(defaultfont_);
158 return true; // no errors
190 TC_ADDTOHTMLPREAMBLE,
199 LexerKeyword textClassTags[] = {
200 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
201 { "addtopreamble", TC_ADDTOPREAMBLE },
202 { "classoptions", TC_CLASSOPTIONS },
203 { "columns", TC_COLUMNS },
204 { "counter", TC_COUNTER },
205 { "defaultfont", TC_DEFAULTFONT },
206 { "defaultmodule", TC_DEFAULTMODULE },
207 { "defaultstyle", TC_DEFAULTSTYLE },
208 { "excludesmodule", TC_EXCLUDESMODULE },
209 { "float", TC_FLOAT },
210 { "format", TC_FORMAT },
211 { "htmlpreamble", TC_HTMLPREAMBLE },
212 { "input", TC_INPUT },
213 { "insetlayout", TC_INSETLAYOUT },
214 { "leftmargin", TC_LEFTMARGIN },
215 { "nofloat", TC_NOFLOAT },
216 { "nostyle", TC_NOSTYLE },
217 { "outputformat", TC_OUTPUTFORMAT },
218 { "outputtype", TC_OUTPUTTYPE },
219 { "pagestyle", TC_PAGESTYLE },
220 { "preamble", TC_PREAMBLE },
221 { "provides", TC_PROVIDES },
222 { "providesmodule", TC_PROVIDESMODULE },
223 { "requires", TC_REQUIRES },
224 { "rightmargin", TC_RIGHTMARGIN },
225 { "secnumdepth", TC_SECNUMDEPTH },
226 { "sides", TC_SIDES },
227 { "style", TC_STYLE },
228 { "titlelatexname", TC_TITLELATEXNAME },
229 { "titlelatextype", TC_TITLELATEXTYPE },
230 { "tocdepth", TC_TOCDEPTH }
236 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
238 LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
239 FileName const tempfile = FileName::tempName("convert_layout");
240 bool success = layout2layout(filename, tempfile);
242 success = readWithoutConv(tempfile, rt) == OK;
243 tempfile.removeFile();
248 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
250 if (!filename.isReadableFile()) {
251 lyxerr << "Cannot read layout file `" << filename << "'."
256 LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
257 to_utf8(makeDisplayPath(filename.absFilename())));
259 // Define the plain layout used in table cells, ert, etc. Note that
260 // we do this before loading any layout file, so that classes can
261 // override features of this layout if they should choose to do so.
262 if (rt == BASECLASS && !hasLayout(plain_layout_))
263 layoutlist_.push_back(createBasicLayout(plain_layout_));
265 Lexer lexrc(textClassTags);
266 lexrc.setFile(filename);
267 ReturnValues retval = read(lexrc, rt);
269 LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
270 to_utf8(makeDisplayPath(filename.absFilename())));
276 bool TextClass::read(FileName const & filename, ReadType rt)
278 ReturnValues const retval = readWithoutConv(filename, rt);
279 if (retval != FORMAT_MISMATCH)
282 bool const worx = convertLayoutFormat(filename, rt);
284 LYXERR0 ("Unable to convert " << filename <<
285 " to format " << FORMAT);
292 bool TextClass::validate(std::string const & str)
295 return tc.read(str, VALIDATION);
299 bool TextClass::read(std::string const & str, ReadType rt)
301 Lexer lexrc(textClassTags);
302 istringstream is(str);
304 ReturnValues retval = read(lexrc, rt);
306 if (retval != FORMAT_MISMATCH)
309 // write the layout string to a temporary file
310 FileName const tempfile = FileName::tempName("TextClass_read");
311 ofstream os(tempfile.toFilesystemEncoding().c_str());
313 LYXERR0("Unable to create temporary file");
319 // now try to convert it
320 bool const worx = convertLayoutFormat(tempfile, rt);
322 LYXERR0("Unable to convert internal layout information to format "
325 tempfile.removeFile();
330 // Reads a textclass structure from file.
331 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
333 bool error = !lexrc.isOK();
335 // Format of files before the 'Format' tag was introduced
339 while (lexrc.isOK() && !error) {
340 int le = lexrc.lex();
343 case Lexer::LEX_FEOF:
346 case Lexer::LEX_UNDEF:
347 lexrc.printError("Unknown TextClass tag `$$Token'");
355 switch (static_cast<TextClassTags>(le)) {
359 format = lexrc.getInteger();
362 case TC_OUTPUTFORMAT:
364 outputFormat_ = lexrc.getString();
368 readOutputType(lexrc);
369 switch(outputType_) {
371 outputFormat_ = "latex";
374 outputFormat_ = "docbook";
377 outputFormat_ = "literate";
382 case TC_INPUT: // Include file
384 string const inc = lexrc.getString();
385 FileName tmp = libFileSearch("layouts", inc,
389 lexrc.printError("Could not find input file: " + inc);
391 } else if (!read(tmp, MERGE)) {
392 lexrc.printError("Error reading input"
393 "file: " + tmp.absFilename());
399 case TC_DEFAULTSTYLE:
401 docstring const name = from_utf8(subst(lexrc.getString(),
403 defaultlayout_ = name;
409 lexrc.printError("No name given for style: `$$Token'.");
413 docstring const name = from_utf8(subst(lexrc.getString(),
416 string s = "Could not read name for style: `$$Token' "
417 + lexrc.getString() + " is probably not valid UTF-8!";
418 lexrc.printError(s.c_str());
420 // Since we couldn't read the name, we just scan the rest
421 // of the style and discard it.
422 error = !readStyle(lexrc, lay);
423 } else if (hasLayout(name)) {
424 Layout & lay = operator[](name);
425 error = !readStyle(lexrc, lay);
428 layout.setName(name);
429 error = !readStyle(lexrc, layout);
431 layoutlist_.push_back(layout);
433 if (defaultlayout_.empty()) {
434 // We do not have a default layout yet, so we choose
435 // the first layout we encounter.
436 defaultlayout_ = name;
444 docstring const style = from_utf8(subst(lexrc.getString(),
446 if (!deleteLayout(style))
447 lyxerr << "Cannot delete style `"
448 << to_utf8(style) << '\'' << endl;
454 columns_ = lexrc.getInteger();
459 switch (lexrc.getInteger()) {
460 case 1: sides_ = OneSide; break;
461 case 2: sides_ = TwoSides; break;
463 lyxerr << "Impossible number of page"
464 " sides, setting to one."
474 pagestyle_ = rtrim(lexrc.getString());
478 defaultfont_ = lyxRead(lexrc);
479 if (!defaultfont_.resolved()) {
480 lexrc.printError("Warning: defaultfont should "
481 "be fully instantiated!");
482 defaultfont_.realize(sane_font);
488 secnumdepth_ = lexrc.getInteger();
493 tocdepth_ = lexrc.getInteger();
496 // First step to support options
497 case TC_CLASSOPTIONS:
498 readClassOptions(lexrc);
502 preamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
505 case TC_HTMLPREAMBLE:
506 htmlpreamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
509 case TC_ADDTOPREAMBLE:
510 preamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
513 case TC_ADDTOHTMLPREAMBLE:
514 htmlpreamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
519 string const feature = lexrc.getString();
521 if (lexrc.getInteger())
522 provides_.insert(feature);
524 provides_.erase(feature);
530 vector<string> const req
531 = getVectorFromString(lexrc.getString());
532 requires_.insert(req.begin(), req.end());
536 case TC_DEFAULTMODULE: {
538 string const module = lexrc.getString();
539 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
540 default_modules_.push_back(module);
544 case TC_PROVIDESMODULE: {
546 string const module = lexrc.getString();
547 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
548 provided_modules_.push_back(module);
552 case TC_EXCLUDESMODULE: {
554 string const module = lexrc.getString();
555 // modules already have their own way to exclude other modules
557 LYXERR0("ExcludesModule tag cannot be used in a module!");
560 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
561 excluded_modules_.push_back(module);
565 case TC_LEFTMARGIN: // left margin type
567 leftmargin_ = lexrc.getDocString();
570 case TC_RIGHTMARGIN: // right margin type
572 rightmargin_ = lexrc.getDocString();
575 case TC_INSETLAYOUT: {
577 lexrc.printError("No name given for InsetLayout: `$$Token'.");
581 docstring const name = subst(lexrc.getDocString(), '_', ' ');
583 string s = "Could not read name for InsetLayout: `$$Token' "
584 + lexrc.getString() + " is probably not valid UTF-8!";
585 lexrc.printError(s.c_str());
587 // Since we couldn't read the name, we just scan the rest
588 // of the style and discard it.
589 il.read(lexrc, *this);
591 } else if (hasInsetLayout(name)) {
592 InsetLayout & il = insetlayoutlist_[name];
593 error = !il.read(lexrc, *this);
597 error = !il.read(lexrc, *this);
599 insetlayoutlist_[name] = il;
610 docstring const name = lexrc.getDocString();
612 string s = "Could not read name for counter: `$$Token' "
613 + lexrc.getString() + " is probably not valid UTF-8!";
614 lexrc.printError(s.c_str());
616 // Since we couldn't read the name, we just scan the rest
620 error = !counters_.read(lexrc, name);
623 lexrc.printError("No name given for style: `$$Token'.");
628 case TC_TITLELATEXTYPE:
629 readTitleType(lexrc);
632 case TC_TITLELATEXNAME:
634 titlename_ = lexrc.getString();
639 string const nofloat = lexrc.getString();
640 floatlist_.erase(nofloat);
645 //Note that this is triggered the first time through the loop unless
646 //we hit a format tag.
647 if (format != FORMAT)
651 if (format != FORMAT)
652 return FORMAT_MISMATCH;
655 return (error ? ERROR : OK);
657 if (defaultlayout_.empty()) {
658 LYXERR0("Error: Textclass '" << name_
659 << "' is missing a defaultstyle.");
663 // Try to erase "stdinsets" from the provides_ set.
665 // Provides stdinsets 1
666 // declaration simply tells us that the standard insets have been
667 // defined. (It's found in stdinsets.inc but could also be used in
668 // user-defined files.) There isn't really any such package. So we
669 // might as well go ahead and erase it.
670 // If we do not succeed, then it was not there, which means that
671 // the textclass did not provide the definitions of the standard
672 // insets. So we need to try to load them.
673 int erased = provides_.erase("stdinsets");
675 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
678 throw ExceptionMessage(WarningException, _("Missing File"),
679 _("Could not find stdinsets.inc! This may lead to data loss!"));
681 } else if (!read(tmp, MERGE)) {
682 throw ExceptionMessage(WarningException, _("Corrupt File"),
683 _("Could not read stdinsets.inc! This may lead to data loss!"));
688 min_toclevel_ = Layout::NOT_IN_TOC;
689 max_toclevel_ = Layout::NOT_IN_TOC;
690 const_iterator lit = begin();
691 const_iterator len = end();
692 for (; lit != len; ++lit) {
693 int const toclevel = lit->toclevel;
694 if (toclevel != Layout::NOT_IN_TOC) {
695 if (min_toclevel_ == Layout::NOT_IN_TOC)
696 min_toclevel_ = toclevel;
698 min_toclevel_ = min(min_toclevel_, toclevel);
699 max_toclevel_ = max(max_toclevel_, toclevel);
702 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
703 << ", maximum is " << max_toclevel_);
705 return (error ? ERROR : OK);
709 void TextClass::readTitleType(Lexer & lexrc)
711 LexerKeyword titleTypeTags[] = {
712 { "commandafter", TITLE_COMMAND_AFTER },
713 { "environment", TITLE_ENVIRONMENT }
716 PushPopHelper pph(lexrc, titleTypeTags);
718 int le = lexrc.lex();
720 case Lexer::LEX_UNDEF:
721 lexrc.printError("Unknown output type `$$Token'");
723 case TITLE_COMMAND_AFTER:
724 case TITLE_ENVIRONMENT:
725 titletype_ = static_cast<TitleLatexType>(le);
728 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
734 void TextClass::readOutputType(Lexer & lexrc)
736 LexerKeyword outputTypeTags[] = {
737 { "docbook", DOCBOOK },
739 { "literate", LITERATE }
742 PushPopHelper pph(lexrc, outputTypeTags);
744 int le = lexrc.lex();
746 case Lexer::LEX_UNDEF:
747 lexrc.printError("Unknown output type `$$Token'");
752 outputType_ = static_cast<OutputType>(le);
755 LYXERR0("Unhandled value " << le);
761 void TextClass::readClassOptions(Lexer & lexrc)
771 LexerKeyword classOptionsTags[] = {
773 {"fontsize", CO_FONTSIZE },
774 {"header", CO_HEADER },
775 {"other", CO_OTHER },
776 {"pagestyle", CO_PAGESTYLE }
779 lexrc.pushTable(classOptionsTags);
781 while (!getout && lexrc.isOK()) {
782 int le = lexrc.lex();
784 case Lexer::LEX_UNDEF:
785 lexrc.printError("Unknown ClassOption tag `$$Token'");
792 opt_fontsize_ = rtrim(lexrc.getString());
796 opt_pagestyle_ = rtrim(lexrc.getString());
800 options_ = lexrc.getString();
804 class_header_ = subst(lexrc.getString(), """, "\"");
815 void TextClass::readFloat(Lexer & lexrc)
832 LexerKeyword floatTags[] = {
834 { "extension", FT_EXT },
835 { "guiname", FT_NAME },
836 { "htmlclass", FT_HTMLCLASS },
837 { "htmlstyle", FT_HTMLSTYLE },
838 { "htmltype", FT_HTMLTYPE },
839 { "latexbuiltin", FT_BUILTIN },
840 { "listname", FT_LISTNAME },
841 { "numberwithin", FT_WITHIN },
842 { "placement", FT_PLACEMENT },
843 { "style", FT_STYLE },
847 lexrc.pushTable(floatTags);
859 bool builtin = false;
862 while (!getout && lexrc.isOK()) {
863 int le = lexrc.lex();
865 case Lexer::LEX_UNDEF:
866 lexrc.printError("Unknown float tag `$$Token'");
873 type = lexrc.getString();
874 if (floatlist_.typeExist(type)) {
875 Floating const & fl = floatlist_.getType(type);
876 placement = fl.placement();
878 within = fl.within();
881 listName = fl.listName();
882 builtin = fl.builtin();
887 name = lexrc.getString();
891 placement = lexrc.getString();
895 ext = lexrc.getString();
899 within = lexrc.getString();
900 if (within == "none")
905 style = lexrc.getString();
909 listName = lexrc.getString();
913 builtin = lexrc.getBool();
917 htmlclass = lexrc.getString();
921 htmlstyle = lexrc.getLongString("EndHTMLStyle");
925 htmltype = lexrc.getString();
933 // Here if have a full float if getout == true
935 Floating fl(type, placement, ext, within, style, name,
936 listName, htmltype, htmlclass, htmlstyle, builtin);
937 floatlist_.newFloat(fl);
938 // each float has its own counter
939 counters_.newCounter(from_ascii(type), from_ascii(within),
940 docstring(), docstring());
941 // also define sub-float counters
942 docstring const subtype = "sub-" + from_ascii(type);
943 counters_.newCounter(subtype, from_ascii(type),
944 "\\alph{" + subtype + "}", docstring());
951 bool TextClass::hasLayout(docstring const & n) const
953 docstring const name = n.empty() ? defaultLayoutName() : n;
955 return find_if(layoutlist_.begin(), layoutlist_.end(),
956 LayoutNamesEqual(name))
957 != layoutlist_.end();
961 bool TextClass::hasInsetLayout(docstring const & n) const
965 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
966 InsetLayouts::const_iterator en = insetlayoutlist_.end();
967 for (; it != en; ++it)
974 Layout const & TextClass::operator[](docstring const & name) const
976 LASSERT(!name.empty(), /**/);
979 find_if(begin(), end(), LayoutNamesEqual(name));
982 lyxerr << "We failed to find the layout '" << to_utf8(name)
983 << "' in the layout list. You MUST investigate!"
985 for (const_iterator cit = begin(); cit != end(); ++cit)
986 lyxerr << " " << to_utf8(cit->name()) << endl;
988 // we require the name to exist
989 LASSERT(false, /**/);
996 Layout & TextClass::operator[](docstring const & name)
998 LASSERT(!name.empty(), /**/);
1000 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1003 LYXERR0("We failed to find the layout '" << to_utf8(name)
1004 << "' in the layout list. You MUST investigate!");
1005 for (const_iterator cit = begin(); cit != end(); ++cit)
1006 LYXERR0(" " << to_utf8(cit->name()));
1008 // we require the name to exist
1009 LASSERT(false, /**/);
1016 bool TextClass::deleteLayout(docstring const & name)
1018 if (name == defaultLayoutName() || name == plainLayoutName())
1021 LayoutList::iterator it =
1022 remove_if(layoutlist_.begin(), layoutlist_.end(),
1023 LayoutNamesEqual(name));
1025 LayoutList::iterator end = layoutlist_.end();
1026 bool const ret = (it != end);
1027 layoutlist_.erase(it, end);
1032 // Load textclass info if not loaded yet
1033 bool TextClass::load(string const & path) const
1038 // Read style-file, provided path is searched before the system ones
1039 // If path is a file, it is loaded directly.
1040 FileName layout_file(path);
1041 if (!path.empty() && !layout_file.isReadableFile())
1042 layout_file = FileName(addName(path, name_ + ".layout"));
1043 if (layout_file.empty() || !layout_file.exists())
1044 layout_file = libFileSearch("layouts", name_, "layout");
1045 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1048 lyxerr << "Error reading `"
1049 << to_utf8(makeDisplayPath(layout_file.absFilename()))
1050 << "'\n(Check `" << name_
1051 << "')\nCheck your installation and "
1052 "try Options/Reconfigure..." << endl;
1059 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1062 layoutlist_.push_back(createBasicLayout(n, true));
1066 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1068 // FIXME The fix for the InsetLayout part of 4812 would be here:
1069 // Add the InsetLayout to the document class if it is not found.
1071 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1072 while (!n.empty()) {
1073 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1074 if (cit != cen && cit->first == n)
1076 size_t i = n.find(':');
1077 if (i == string::npos)
1081 return plain_insetlayout_;
1085 docstring const & TextClass::defaultLayoutName() const
1087 // This really should come from the actual layout... (Lgb)
1088 return defaultlayout_;
1092 Layout const & TextClass::defaultLayout() const
1094 return operator[](defaultLayoutName());
1098 bool TextClass::isDefaultLayout(Layout const & layout) const
1100 return layout.name() == defaultLayoutName();
1104 bool TextClass::isPlainLayout(Layout const & layout) const
1106 return layout.name() == plainLayoutName();
1110 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1112 static Layout * defaultLayout = NULL;
1114 if (defaultLayout) {
1115 defaultLayout->setUnknown(unknown);
1116 defaultLayout->setName(name);
1117 return *defaultLayout;
1120 static char const * s = "Margin Static\n"
1121 "LatexType Paragraph\n"
1124 "AlignPossible Left, Right, Center\n"
1125 "LabelType No_Label\n"
1127 istringstream ss(s);
1128 Lexer lex(textClassTags);
1130 defaultLayout = new Layout;
1131 defaultLayout->setUnknown(unknown);
1132 defaultLayout->setName(name);
1133 if (!readStyle(lex, *defaultLayout)) {
1134 // The only way this happens is because the hardcoded layout above
1136 LASSERT(false, /**/);
1138 return *defaultLayout;
1141 /////////////////////////////////////////////////////////////////////////
1143 // DocumentClassBundle
1145 /////////////////////////////////////////////////////////////////////////
1147 DocumentClassBundle::~DocumentClassBundle()
1149 for (size_t i = 0; i != documentClasses_.size(); ++i)
1150 delete documentClasses_[i];
1151 documentClasses_.clear();
1154 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1156 DocumentClass * dc = new DocumentClass(baseClass);
1157 documentClasses_.push_back(dc);
1158 return *documentClasses_.back();
1162 DocumentClassBundle & DocumentClassBundle::get()
1164 static DocumentClassBundle singleton;
1169 DocumentClass & DocumentClassBundle::makeDocumentClass(
1170 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1172 DocumentClass & doc_class = newClass(baseClass);
1173 LayoutModuleList::const_iterator it = modlist.begin();
1174 LayoutModuleList::const_iterator en = modlist.end();
1175 for (; it != en; it++) {
1176 string const modName = *it;
1177 LyXModule * lm = moduleList[modName];
1179 docstring const msg =
1180 bformat(_("The module %1$s has been requested by\n"
1181 "this document but has not been found in the list of\n"
1182 "available modules. If you recently installed it, you\n"
1183 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1184 ExceptionMessage(WarningException,_("Module not available"),
1185 msg + _("Some layouts may not be available."));
1188 if (!lm->isAvailable()) {
1189 docstring const msg =
1190 bformat(_("The module %1$s requires a package that is\n"
1191 "not available in your LaTeX installation. LaTeX output\n"
1192 "may not be possible.\n"), from_utf8(modName));
1193 ExceptionMessage(WarningException, _("Package not available"), msg);
1195 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1196 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1197 docstring const msg =
1198 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1199 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1206 /////////////////////////////////////////////////////////////////////////
1210 /////////////////////////////////////////////////////////////////////////
1212 DocumentClass::DocumentClass(LayoutFile const & tc)
1217 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1219 LayoutList::const_iterator it = layoutlist_.begin();
1220 LayoutList::const_iterator end = layoutlist_.end();
1221 for (; it != end; ++it)
1222 if (it->latexname() == lay)
1228 bool DocumentClass::provides(string const & p) const
1230 return provides_.find(p) != provides_.end();
1234 bool DocumentClass::hasTocLevels() const
1236 return min_toclevel_ != Layout::NOT_IN_TOC;
1240 /////////////////////////////////////////////////////////////////////////
1244 /////////////////////////////////////////////////////////////////////////
1246 ostream & operator<<(ostream & os, PageSides p)