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 = 21;
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 std::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,
206 LexerKeyword textClassTags[] = {
207 { "addtohtmlpreamble", TC_ADDTOHTMLPREAMBLE },
208 { "addtopreamble", TC_ADDTOPREAMBLE },
209 { "classoptions", TC_CLASSOPTIONS },
210 { "columns", TC_COLUMNS },
211 { "counter", TC_COUNTER },
212 { "defaultfont", TC_DEFAULTFONT },
213 { "defaultmodule", TC_DEFAULTMODULE },
214 { "defaultstyle", TC_DEFAULTSTYLE },
215 { "excludesmodule", TC_EXCLUDESMODULE },
216 { "float", TC_FLOAT },
217 { "format", TC_FORMAT },
218 { "htmlpreamble", TC_HTMLPREAMBLE },
219 { "htmltocsection", TC_HTMLTOCSECTION },
220 { "ifcounter", TC_IFCOUNTER },
221 { "ifstyle", TC_IFSTYLE },
222 { "input", TC_INPUT },
223 { "insetlayout", TC_INSETLAYOUT },
224 { "leftmargin", TC_LEFTMARGIN },
225 { "nofloat", TC_NOFLOAT },
226 { "nostyle", TC_NOSTYLE },
227 { "outputformat", TC_OUTPUTFORMAT },
228 { "outputtype", TC_OUTPUTTYPE },
229 { "pagestyle", TC_PAGESTYLE },
230 { "preamble", TC_PREAMBLE },
231 { "provides", TC_PROVIDES },
232 { "providesmodule", TC_PROVIDESMODULE },
233 { "requires", TC_REQUIRES },
234 { "rightmargin", TC_RIGHTMARGIN },
235 { "secnumdepth", TC_SECNUMDEPTH },
236 { "sides", TC_SIDES },
237 { "style", TC_STYLE },
238 { "titlelatexname", TC_TITLELATEXNAME },
239 { "titlelatextype", TC_TITLELATEXTYPE },
240 { "tocdepth", TC_TOCDEPTH }
246 bool TextClass::convertLayoutFormat(support::FileName const & filename, ReadType rt)
248 LYXERR(Debug::TCLASS, "Converting layout file to " << FORMAT);
249 FileName const tempfile = FileName::tempName("convert_layout");
250 bool success = layout2layout(filename, tempfile);
252 success = readWithoutConv(tempfile, rt) == OK;
253 tempfile.removeFile();
258 TextClass::ReturnValues TextClass::readWithoutConv(FileName const & filename, ReadType rt)
260 if (!filename.isReadableFile()) {
261 lyxerr << "Cannot read layout file `" << filename << "'."
266 LYXERR(Debug::TCLASS, "Reading " + translateRT(rt) + ": " +
267 to_utf8(makeDisplayPath(filename.absFilename())));
269 // Define the plain layout used in table cells, ert, etc. Note that
270 // we do this before loading any layout file, so that classes can
271 // override features of this layout if they should choose to do so.
272 if (rt == BASECLASS && !hasLayout(plain_layout_))
273 layoutlist_.push_back(createBasicLayout(plain_layout_));
275 Lexer lexrc(textClassTags);
276 lexrc.setFile(filename);
277 ReturnValues retval = read(lexrc, rt);
279 LYXERR(Debug::TCLASS, "Finished reading " + translateRT(rt) + ": " +
280 to_utf8(makeDisplayPath(filename.absFilename())));
286 bool TextClass::read(FileName const & filename, ReadType rt)
288 ReturnValues const retval = readWithoutConv(filename, rt);
289 if (retval != FORMAT_MISMATCH)
292 bool const worx = convertLayoutFormat(filename, rt);
294 LYXERR0 ("Unable to convert " << filename <<
295 " to format " << FORMAT);
302 bool TextClass::validate(std::string const & str)
305 return tc.read(str, VALIDATION);
309 bool TextClass::read(std::string const & str, ReadType rt)
311 Lexer lexrc(textClassTags);
312 istringstream is(str);
314 ReturnValues retval = read(lexrc, rt);
316 if (retval != FORMAT_MISMATCH)
319 // write the layout string to a temporary file
320 FileName const tempfile = FileName::tempName("TextClass_read");
321 ofstream os(tempfile.toFilesystemEncoding().c_str());
323 LYXERR0("Unable to create temporary file");
329 // now try to convert it
330 bool const worx = convertLayoutFormat(tempfile, rt);
332 LYXERR0("Unable to convert internal layout information to format "
335 tempfile.removeFile();
340 // Reads a textclass structure from file.
341 TextClass::ReturnValues TextClass::read(Lexer & lexrc, ReadType rt)
343 bool error = !lexrc.isOK();
345 // Format of files before the 'Format' tag was introduced
349 while (lexrc.isOK() && !error) {
350 int le = lexrc.lex();
353 case Lexer::LEX_FEOF:
356 case Lexer::LEX_UNDEF:
357 lexrc.printError("Unknown TextClass tag `$$Token'");
365 // used below to track whether we are in an IfStyle or IfCounter tag.
366 bool ifstyle = false;
367 bool ifcounter = false;
369 switch (static_cast<TextClassTags>(le)) {
373 format = lexrc.getInteger();
376 case TC_OUTPUTFORMAT:
378 outputFormat_ = lexrc.getString();
382 readOutputType(lexrc);
383 switch(outputType_) {
385 outputFormat_ = "latex";
388 outputFormat_ = "docbook";
391 outputFormat_ = "literate";
396 case TC_INPUT: // Include file
398 string const inc = lexrc.getString();
399 FileName tmp = libFileSearch("layouts", inc,
403 lexrc.printError("Could not find input file: " + inc);
405 } else if (!read(tmp, MERGE)) {
406 lexrc.printError("Error reading input"
407 "file: " + tmp.absFilename());
413 case TC_DEFAULTSTYLE:
415 docstring const name = from_utf8(subst(lexrc.getString(),
417 defaultlayout_ = name;
426 lexrc.printError("No name given for style: `$$Token'.");
430 docstring const name = from_utf8(subst(lexrc.getString(),
433 string s = "Could not read name for style: `$$Token' "
434 + lexrc.getString() + " is probably not valid UTF-8!";
435 lexrc.printError(s.c_str());
437 // Since we couldn't read the name, we just scan the rest
438 // of the style and discard it.
439 error = !readStyle(lexrc, lay);
440 } else if (hasLayout(name)) {
441 Layout & lay = operator[](name);
442 error = !readStyle(lexrc, lay);
443 } else if (!ifstyle) {
445 layout.setName(name);
446 error = !readStyle(lexrc, layout);
448 layoutlist_.push_back(layout);
450 if (defaultlayout_.empty()) {
451 // We do not have a default layout yet, so we choose
452 // the first layout we encounter.
453 defaultlayout_ = name;
457 // scan the rest and discard it
459 readStyle(lexrc, lay);
470 docstring const style = from_utf8(subst(lexrc.getString(),
472 if (!deleteLayout(style))
473 lyxerr << "Cannot delete style `"
474 << to_utf8(style) << '\'' << endl;
480 columns_ = lexrc.getInteger();
485 switch (lexrc.getInteger()) {
486 case 1: sides_ = OneSide; break;
487 case 2: sides_ = TwoSides; break;
489 lyxerr << "Impossible number of page"
490 " sides, setting to one."
500 pagestyle_ = rtrim(lexrc.getString());
504 defaultfont_ = lyxRead(lexrc);
505 if (!defaultfont_.resolved()) {
506 lexrc.printError("Warning: defaultfont should "
507 "be fully instantiated!");
508 defaultfont_.realize(sane_font);
514 secnumdepth_ = lexrc.getInteger();
519 tocdepth_ = lexrc.getInteger();
522 // First step to support options
523 case TC_CLASSOPTIONS:
524 readClassOptions(lexrc);
528 preamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
531 case TC_HTMLPREAMBLE:
532 htmlpreamble_ = from_utf8(lexrc.getLongString("EndPreamble"));
535 case TC_HTMLTOCSECTION:
536 html_toc_section_ = from_utf8(trim(lexrc.getString()));
539 case TC_ADDTOPREAMBLE:
540 preamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
543 case TC_ADDTOHTMLPREAMBLE:
544 htmlpreamble_ += from_utf8(lexrc.getLongString("EndPreamble"));
549 string const feature = lexrc.getString();
551 if (lexrc.getInteger())
552 provides_.insert(feature);
554 provides_.erase(feature);
560 vector<string> const req
561 = getVectorFromString(lexrc.getString());
562 requires_.insert(req.begin(), req.end());
566 case TC_DEFAULTMODULE: {
568 string const module = lexrc.getString();
569 if (find(default_modules_.begin(), default_modules_.end(), module) == default_modules_.end())
570 default_modules_.push_back(module);
574 case TC_PROVIDESMODULE: {
576 string const module = lexrc.getString();
577 if (find(provided_modules_.begin(), provided_modules_.end(), module) == provided_modules_.end())
578 provided_modules_.push_back(module);
582 case TC_EXCLUDESMODULE: {
584 string const module = lexrc.getString();
585 // modules already have their own way to exclude other modules
587 LYXERR0("ExcludesModule tag cannot be used in a module!");
590 if (find(excluded_modules_.begin(), excluded_modules_.end(), module) == excluded_modules_.end())
591 excluded_modules_.push_back(module);
595 case TC_LEFTMARGIN: // left margin type
597 leftmargin_ = lexrc.getDocString();
600 case TC_RIGHTMARGIN: // right margin type
602 rightmargin_ = lexrc.getDocString();
605 case TC_INSETLAYOUT: {
607 lexrc.printError("No name given for InsetLayout: `$$Token'.");
611 docstring const name = subst(lexrc.getDocString(), '_', ' ');
613 string s = "Could not read name for InsetLayout: `$$Token' "
614 + lexrc.getString() + " is probably not valid UTF-8!";
615 lexrc.printError(s.c_str());
617 // Since we couldn't read the name, we just scan the rest
618 // of the style and discard it.
619 il.read(lexrc, *this);
621 } else if (hasInsetLayout(name)) {
622 InsetLayout & il = insetlayoutlist_[name];
623 error = !il.read(lexrc, *this);
625 InsetLayout il(name);
626 error = !il.read(lexrc, *this);
628 insetlayoutlist_[name] = il;
641 docstring const name = lexrc.getDocString();
643 string s = "Could not read name for counter: `$$Token' "
644 + lexrc.getString() + " is probably not valid UTF-8!";
645 lexrc.printError(s.c_str());
647 // Since we couldn't read the name, we just scan the rest
651 error = !counters_.read(lexrc, name, !ifcounter);
654 lexrc.printError("No name given for style: `$$Token'.");
661 case TC_TITLELATEXTYPE:
662 readTitleType(lexrc);
665 case TC_TITLELATEXNAME:
667 titlename_ = lexrc.getString();
672 string const nofloat = lexrc.getString();
673 floatlist_.erase(nofloat);
678 //Note that this is triggered the first time through the loop unless
679 //we hit a format tag.
680 if (format != FORMAT)
684 if (format != FORMAT)
685 return FORMAT_MISMATCH;
688 return (error ? ERROR : OK);
690 if (defaultlayout_.empty()) {
691 LYXERR0("Error: Textclass '" << name_
692 << "' is missing a defaultstyle.");
696 // Try to erase "stdinsets" from the provides_ set.
698 // Provides stdinsets 1
699 // declaration simply tells us that the standard insets have been
700 // defined. (It's found in stdinsets.inc but could also be used in
701 // user-defined files.) There isn't really any such package. So we
702 // might as well go ahead and erase it.
703 // If we do not succeed, then it was not there, which means that
704 // the textclass did not provide the definitions of the standard
705 // insets. So we need to try to load them.
706 int erased = provides_.erase("stdinsets");
708 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
711 throw ExceptionMessage(WarningException, _("Missing File"),
712 _("Could not find stdinsets.inc! This may lead to data loss!"));
714 } else if (!read(tmp, MERGE)) {
715 throw ExceptionMessage(WarningException, _("Corrupt File"),
716 _("Could not read stdinsets.inc! This may lead to data loss!"));
721 min_toclevel_ = Layout::NOT_IN_TOC;
722 max_toclevel_ = Layout::NOT_IN_TOC;
723 const_iterator lit = begin();
724 const_iterator len = end();
725 for (; lit != len; ++lit) {
726 int const toclevel = lit->toclevel;
727 if (toclevel != Layout::NOT_IN_TOC) {
728 if (min_toclevel_ == Layout::NOT_IN_TOC)
729 min_toclevel_ = toclevel;
731 min_toclevel_ = min(min_toclevel_, toclevel);
732 max_toclevel_ = max(max_toclevel_, toclevel);
735 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
736 << ", maximum is " << max_toclevel_);
738 return (error ? ERROR : OK);
742 void TextClass::readTitleType(Lexer & lexrc)
744 LexerKeyword titleTypeTags[] = {
745 { "commandafter", TITLE_COMMAND_AFTER },
746 { "environment", TITLE_ENVIRONMENT }
749 PushPopHelper pph(lexrc, titleTypeTags);
751 int le = lexrc.lex();
753 case Lexer::LEX_UNDEF:
754 lexrc.printError("Unknown output type `$$Token'");
756 case TITLE_COMMAND_AFTER:
757 case TITLE_ENVIRONMENT:
758 titletype_ = static_cast<TitleLatexType>(le);
761 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
767 void TextClass::readOutputType(Lexer & lexrc)
769 LexerKeyword outputTypeTags[] = {
770 { "docbook", DOCBOOK },
772 { "literate", LITERATE }
775 PushPopHelper pph(lexrc, outputTypeTags);
777 int le = lexrc.lex();
779 case Lexer::LEX_UNDEF:
780 lexrc.printError("Unknown output type `$$Token'");
785 outputType_ = static_cast<OutputType>(le);
788 LYXERR0("Unhandled value " << le);
794 void TextClass::readClassOptions(Lexer & lexrc)
804 LexerKeyword classOptionsTags[] = {
806 {"fontsize", CO_FONTSIZE },
807 {"header", CO_HEADER },
808 {"other", CO_OTHER },
809 {"pagestyle", CO_PAGESTYLE }
812 lexrc.pushTable(classOptionsTags);
814 while (!getout && lexrc.isOK()) {
815 int le = lexrc.lex();
817 case Lexer::LEX_UNDEF:
818 lexrc.printError("Unknown ClassOption tag `$$Token'");
825 opt_fontsize_ = rtrim(lexrc.getString());
829 opt_pagestyle_ = rtrim(lexrc.getString());
833 options_ = lexrc.getString();
837 class_header_ = subst(lexrc.getString(), """, "\"");
848 void TextClass::readFloat(Lexer & lexrc)
865 LexerKeyword floatTags[] = {
867 { "extension", FT_EXT },
868 { "guiname", FT_NAME },
869 { "htmlattr", FT_HTMLATTR },
870 { "htmlstyle", FT_HTMLSTYLE },
871 { "htmltag", FT_HTMLTAG },
872 { "latexbuiltin", FT_BUILTIN },
873 { "listname", FT_LISTNAME },
874 { "numberwithin", FT_WITHIN },
875 { "placement", FT_PLACEMENT },
876 { "style", FT_STYLE },
880 lexrc.pushTable(floatTags);
892 bool builtin = false;
895 while (!getout && lexrc.isOK()) {
896 int le = lexrc.lex();
898 case Lexer::LEX_UNDEF:
899 lexrc.printError("Unknown float tag `$$Token'");
906 type = lexrc.getString();
907 if (floatlist_.typeExist(type)) {
908 Floating const & fl = floatlist_.getType(type);
909 placement = fl.placement();
911 within = fl.within();
914 listName = fl.listName();
915 builtin = fl.builtin();
920 name = lexrc.getString();
924 placement = lexrc.getString();
928 ext = lexrc.getString();
932 within = lexrc.getString();
933 if (within == "none")
938 style = lexrc.getString();
942 listName = lexrc.getString();
946 builtin = lexrc.getBool();
950 htmlattr = lexrc.getString();
954 htmlstyle = lexrc.getLongString("EndHTMLStyle");
958 htmltag = lexrc.getString();
966 // Here if have a full float if getout == true
968 Floating fl(type, placement, ext, within, style, name,
969 listName, htmltag, htmlattr, htmlstyle, builtin);
970 floatlist_.newFloat(fl);
971 // each float has its own counter
972 counters_.newCounter(from_ascii(type), from_ascii(within),
973 docstring(), docstring());
974 // also define sub-float counters
975 docstring const subtype = "sub-" + from_ascii(type);
976 counters_.newCounter(subtype, from_ascii(type),
977 "\\alph{" + subtype + "}", docstring());
984 bool TextClass::hasLayout(docstring const & n) const
986 docstring const name = n.empty() ? defaultLayoutName() : n;
988 return find_if(layoutlist_.begin(), layoutlist_.end(),
989 LayoutNamesEqual(name))
990 != layoutlist_.end();
994 bool TextClass::hasInsetLayout(docstring const & n) const
998 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
999 InsetLayouts::const_iterator en = insetlayoutlist_.end();
1000 for (; it != en; ++it)
1007 Layout const & TextClass::operator[](docstring const & name) const
1009 LASSERT(!name.empty(), /**/);
1012 find_if(begin(), end(), LayoutNamesEqual(name));
1015 lyxerr << "We failed to find the layout '" << to_utf8(name)
1016 << "' in the layout list. You MUST investigate!"
1018 for (const_iterator cit = begin(); cit != end(); ++cit)
1019 lyxerr << " " << to_utf8(cit->name()) << endl;
1021 // we require the name to exist
1022 LASSERT(false, /**/);
1029 Layout & TextClass::operator[](docstring const & name)
1031 LASSERT(!name.empty(), /**/);
1033 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1036 LYXERR0("We failed to find the layout '" << to_utf8(name)
1037 << "' in the layout list. You MUST investigate!");
1038 for (const_iterator cit = begin(); cit != end(); ++cit)
1039 LYXERR0(" " << to_utf8(cit->name()));
1041 // we require the name to exist
1042 LASSERT(false, /**/);
1049 bool TextClass::deleteLayout(docstring const & name)
1051 if (name == defaultLayoutName() || name == plainLayoutName())
1054 LayoutList::iterator it =
1055 remove_if(layoutlist_.begin(), layoutlist_.end(),
1056 LayoutNamesEqual(name));
1058 LayoutList::iterator end = layoutlist_.end();
1059 bool const ret = (it != end);
1060 layoutlist_.erase(it, end);
1065 // Load textclass info if not loaded yet
1066 bool TextClass::load(string const & path) const
1071 // Read style-file, provided path is searched before the system ones
1072 // If path is a file, it is loaded directly.
1073 FileName layout_file(path);
1074 if (!path.empty() && !layout_file.isReadableFile())
1075 layout_file = FileName(addName(path, name_ + ".layout"));
1076 if (layout_file.empty() || !layout_file.exists())
1077 layout_file = libFileSearch("layouts", name_, "layout");
1078 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1081 lyxerr << "Error reading `"
1082 << to_utf8(makeDisplayPath(layout_file.absFilename()))
1083 << "'\n(Check `" << name_
1084 << "')\nCheck your installation and "
1085 "try Options/Reconfigure..." << endl;
1092 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1095 layoutlist_.push_back(createBasicLayout(n, true));
1099 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1101 // FIXME The fix for the InsetLayout part of 4812 would be here:
1102 // Add the InsetLayout to the document class if it is not found.
1104 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1105 while (!n.empty()) {
1106 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1107 if (cit != cen && cit->first == n)
1109 size_t i = n.find(':');
1110 if (i == string::npos)
1114 return plain_insetlayout_;
1118 docstring const & TextClass::defaultLayoutName() const
1120 // This really should come from the actual layout... (Lgb)
1121 return defaultlayout_;
1125 Layout const & TextClass::defaultLayout() const
1127 return operator[](defaultLayoutName());
1131 bool TextClass::isDefaultLayout(Layout const & layout) const
1133 return layout.name() == defaultLayoutName();
1137 bool TextClass::isPlainLayout(Layout const & layout) const
1139 return layout.name() == plainLayoutName();
1143 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1145 static Layout * defaultLayout = NULL;
1147 if (defaultLayout) {
1148 defaultLayout->setUnknown(unknown);
1149 defaultLayout->setName(name);
1150 return *defaultLayout;
1153 static char const * s = "Margin Static\n"
1154 "LatexType Paragraph\n"
1157 "AlignPossible Left, Right, Center\n"
1158 "LabelType No_Label\n"
1160 istringstream ss(s);
1161 Lexer lex(textClassTags);
1163 defaultLayout = new Layout;
1164 defaultLayout->setUnknown(unknown);
1165 defaultLayout->setName(name);
1166 if (!readStyle(lex, *defaultLayout)) {
1167 // The only way this happens is because the hardcoded layout above
1169 LASSERT(false, /**/);
1171 return *defaultLayout;
1175 /////////////////////////////////////////////////////////////////////////
1177 // DocumentClassBundle
1179 /////////////////////////////////////////////////////////////////////////
1181 DocumentClassBundle::~DocumentClassBundle()
1183 for (size_t i = 0; i != documentClasses_.size(); ++i)
1184 delete documentClasses_[i];
1185 documentClasses_.clear();
1188 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1190 DocumentClass * dc = new DocumentClass(baseClass);
1191 documentClasses_.push_back(dc);
1192 return *documentClasses_.back();
1196 DocumentClassBundle & DocumentClassBundle::get()
1198 static DocumentClassBundle singleton;
1203 DocumentClass & DocumentClassBundle::makeDocumentClass(
1204 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1206 DocumentClass & doc_class = newClass(baseClass);
1207 LayoutModuleList::const_iterator it = modlist.begin();
1208 LayoutModuleList::const_iterator en = modlist.end();
1209 for (; it != en; it++) {
1210 string const modName = *it;
1211 LyXModule * lm = theModuleList[modName];
1213 docstring const msg =
1214 bformat(_("The module %1$s has been requested by\n"
1215 "this document but has not been found in the list of\n"
1216 "available modules. If you recently installed it, you\n"
1217 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1218 ExceptionMessage(WarningException,_("Module not available"),
1219 msg + _("Some layouts may not be available."));
1222 if (!lm->isAvailable()) {
1223 docstring const msg =
1224 bformat(_("The module %1$s requires a package that is\n"
1225 "not available in your LaTeX installation. LaTeX output\n"
1226 "may not be possible.\n"), from_utf8(modName));
1227 ExceptionMessage(WarningException, _("Package not available"), msg);
1229 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1230 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1231 docstring const msg =
1232 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1233 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1240 /////////////////////////////////////////////////////////////////////////
1244 /////////////////////////////////////////////////////////////////////////
1246 DocumentClass::DocumentClass(LayoutFile const & tc)
1251 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1253 LayoutList::const_iterator it = layoutlist_.begin();
1254 LayoutList::const_iterator end = layoutlist_.end();
1255 for (; it != end; ++it)
1256 if (it->latexname() == lay)
1262 bool DocumentClass::provides(string const & p) const
1264 return provides_.find(p) != provides_.end();
1268 bool DocumentClass::hasTocLevels() const
1270 return min_toclevel_ != Layout::NOT_IN_TOC;
1274 Layout const & DocumentClass::htmlTOCLayout() const
1276 if (html_toc_section_.empty()) {
1277 // we're going to look for the layout with the minimum toclevel
1278 TextClass::LayoutList::const_iterator lit = begin();
1279 TextClass::LayoutList::const_iterator const len = end();
1280 int minlevel = 1000;
1281 Layout const * lay = NULL;
1282 for (; lit != len; ++lit) {
1283 int const level = lit->toclevel;
1284 // we don't want Part
1285 if (level == Layout::NOT_IN_TOC || level < 0 || level >= minlevel)
1291 html_toc_section_ = lay->name();
1293 // hmm. that is very odd, so we'll do our best
1294 html_toc_section_ = defaultLayoutName();
1296 return operator[](html_toc_section_);
1300 /////////////////////////////////////////////////////////////////////////
1304 /////////////////////////////////////////////////////////////////////////
1306 ostream & operator<<(ostream & os, PageSides p)