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 = 25;
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,
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);
627 error = !il.read(lexrc, *this);
629 insetlayoutlist_[name] = il;
642 docstring const name = lexrc.getDocString();
644 string s = "Could not read name for counter: `$$Token' "
645 + lexrc.getString() + " is probably not valid UTF-8!";
646 lexrc.printError(s.c_str());
648 // Since we couldn't read the name, we just scan the rest
652 error = !counters_.read(lexrc, name, !ifcounter);
655 lexrc.printError("No name given for style: `$$Token'.");
662 case TC_TITLELATEXTYPE:
663 readTitleType(lexrc);
666 case TC_TITLELATEXNAME:
668 titlename_ = lexrc.getString();
673 string const nofloat = lexrc.getString();
674 floatlist_.erase(nofloat);
679 //Note that this is triggered the first time through the loop unless
680 //we hit a format tag.
681 if (format != FORMAT)
685 if (format != FORMAT)
686 return FORMAT_MISMATCH;
689 return (error ? ERROR : OK);
691 if (defaultlayout_.empty()) {
692 LYXERR0("Error: Textclass '" << name_
693 << "' is missing a defaultstyle.");
697 // Try to erase "stdinsets" from the provides_ set.
699 // Provides stdinsets 1
700 // declaration simply tells us that the standard insets have been
701 // defined. (It's found in stdinsets.inc but could also be used in
702 // user-defined files.) There isn't really any such package. So we
703 // might as well go ahead and erase it.
704 // If we do not succeed, then it was not there, which means that
705 // the textclass did not provide the definitions of the standard
706 // insets. So we need to try to load them.
707 int erased = provides_.erase("stdinsets");
709 FileName tmp = libFileSearch("layouts", "stdinsets.inc");
712 throw ExceptionMessage(WarningException, _("Missing File"),
713 _("Could not find stdinsets.inc! This may lead to data loss!"));
715 } else if (!read(tmp, MERGE)) {
716 throw ExceptionMessage(WarningException, _("Corrupt File"),
717 _("Could not read stdinsets.inc! This may lead to data loss!"));
722 min_toclevel_ = Layout::NOT_IN_TOC;
723 max_toclevel_ = Layout::NOT_IN_TOC;
724 const_iterator lit = begin();
725 const_iterator len = end();
726 for (; lit != len; ++lit) {
727 int const toclevel = lit->toclevel;
728 if (toclevel != Layout::NOT_IN_TOC) {
729 if (min_toclevel_ == Layout::NOT_IN_TOC)
730 min_toclevel_ = toclevel;
732 min_toclevel_ = min(min_toclevel_, toclevel);
733 max_toclevel_ = max(max_toclevel_, toclevel);
736 LYXERR(Debug::TCLASS, "Minimum TocLevel is " << min_toclevel_
737 << ", maximum is " << max_toclevel_);
739 return (error ? ERROR : OK);
743 void TextClass::readTitleType(Lexer & lexrc)
745 LexerKeyword titleTypeTags[] = {
746 { "commandafter", TITLE_COMMAND_AFTER },
747 { "environment", TITLE_ENVIRONMENT }
750 PushPopHelper pph(lexrc, titleTypeTags);
752 int le = lexrc.lex();
754 case Lexer::LEX_UNDEF:
755 lexrc.printError("Unknown output type `$$Token'");
757 case TITLE_COMMAND_AFTER:
758 case TITLE_ENVIRONMENT:
759 titletype_ = static_cast<TitleLatexType>(le);
762 LYXERR0("Unhandled value " << le << " in TextClass::readTitleType.");
768 void TextClass::readOutputType(Lexer & lexrc)
770 LexerKeyword outputTypeTags[] = {
771 { "docbook", DOCBOOK },
773 { "literate", LITERATE }
776 PushPopHelper pph(lexrc, outputTypeTags);
778 int le = lexrc.lex();
780 case Lexer::LEX_UNDEF:
781 lexrc.printError("Unknown output type `$$Token'");
786 outputType_ = static_cast<OutputType>(le);
789 LYXERR0("Unhandled value " << le);
795 void TextClass::readClassOptions(Lexer & lexrc)
805 LexerKeyword classOptionsTags[] = {
807 {"fontsize", CO_FONTSIZE },
808 {"header", CO_HEADER },
809 {"other", CO_OTHER },
810 {"pagestyle", CO_PAGESTYLE }
813 lexrc.pushTable(classOptionsTags);
815 while (!getout && lexrc.isOK()) {
816 int le = lexrc.lex();
818 case Lexer::LEX_UNDEF:
819 lexrc.printError("Unknown ClassOption tag `$$Token'");
826 opt_fontsize_ = rtrim(lexrc.getString());
830 opt_pagestyle_ = rtrim(lexrc.getString());
834 options_ = lexrc.getString();
838 class_header_ = subst(lexrc.getString(), """, "\"");
849 void TextClass::readFloat(Lexer & lexrc)
868 LexerKeyword floatTags[] = {
870 { "extension", FT_EXT },
871 { "guiname", FT_NAME },
872 { "htmlattr", FT_HTMLATTR },
873 { "htmlstyle", FT_HTMLSTYLE },
874 { "htmltag", FT_HTMLTAG },
875 { "listcommand", FT_LISTCOMMAND },
876 { "listname", FT_LISTNAME },
877 { "needsfloatpkg", FT_NEEDSFLOAT },
878 { "numberwithin", FT_WITHIN },
879 { "placement", FT_PLACEMENT },
880 { "refprefix", FT_REFPREFIX },
881 { "style", FT_STYLE },
885 lexrc.pushTable(floatTags);
899 bool needsfloat = true;
902 while (!getout && lexrc.isOK()) {
903 int le = lexrc.lex();
905 case Lexer::LEX_UNDEF:
906 lexrc.printError("Unknown float tag `$$Token'");
913 type = lexrc.getString();
914 if (floatlist_.typeExist(type)) {
915 Floating const & fl = floatlist_.getType(type);
916 placement = fl.placement();
918 within = fl.within();
921 listname = fl.listName();
922 needsfloat = fl.needsFloatPkg();
923 listcommand = fl.listCommand();
924 refprefix = fl.refPrefix();
929 name = lexrc.getString();
933 placement = lexrc.getString();
937 ext = lexrc.getString();
941 within = lexrc.getString();
942 if (within == "none")
947 style = lexrc.getString();
951 listcommand = lexrc.getString();
955 refprefix = lexrc.getString();
959 listname = lexrc.getString();
963 needsfloat = lexrc.getBool();
967 htmlattr = lexrc.getString();
971 htmlstyle = lexrc.getLongString("EndHTMLStyle");
975 htmltag = lexrc.getString();
983 // Here we have a full float if getout == true
985 if (!needsfloat && listcommand.empty())
986 LYXERR0("The layout does not provide a list command " <<
987 "for the builtin float `" << type << "'. LyX will " <<
988 "not be able to produce a float list.");
989 Floating fl(type, placement, ext, within, style, name,
990 listname, listcommand, refprefix,
991 htmltag, htmlattr, htmlstyle, needsfloat);
992 floatlist_.newFloat(fl);
993 // each float has its own counter
994 counters_.newCounter(from_ascii(type), from_ascii(within),
995 docstring(), docstring());
996 // also define sub-float counters
997 docstring const subtype = "sub-" + from_ascii(type);
998 counters_.newCounter(subtype, from_ascii(type),
999 "\\alph{" + subtype + "}", docstring());
1006 bool TextClass::hasLayout(docstring const & n) const
1008 docstring const name = n.empty() ? defaultLayoutName() : n;
1010 return find_if(layoutlist_.begin(), layoutlist_.end(),
1011 LayoutNamesEqual(name))
1012 != layoutlist_.end();
1016 bool TextClass::hasInsetLayout(docstring const & n) const
1020 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
1021 InsetLayouts::const_iterator en = insetlayoutlist_.end();
1022 for (; it != en; ++it)
1029 Layout const & TextClass::operator[](docstring const & name) const
1031 LASSERT(!name.empty(), /**/);
1034 find_if(begin(), end(), LayoutNamesEqual(name));
1037 lyxerr << "We failed to find the layout '" << to_utf8(name)
1038 << "' in the layout list. You MUST investigate!"
1040 for (const_iterator cit = begin(); cit != end(); ++cit)
1041 lyxerr << " " << to_utf8(cit->name()) << endl;
1043 // we require the name to exist
1044 LASSERT(false, /**/);
1051 Layout & TextClass::operator[](docstring const & name)
1053 LASSERT(!name.empty(), /**/);
1055 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1058 LYXERR0("We failed to find the layout '" << to_utf8(name)
1059 << "' in the layout list. You MUST investigate!");
1060 for (const_iterator cit = begin(); cit != end(); ++cit)
1061 LYXERR0(" " << to_utf8(cit->name()));
1063 // we require the name to exist
1064 LASSERT(false, /**/);
1071 bool TextClass::deleteLayout(docstring const & name)
1073 if (name == defaultLayoutName() || name == plainLayoutName())
1076 LayoutList::iterator it =
1077 remove_if(layoutlist_.begin(), layoutlist_.end(),
1078 LayoutNamesEqual(name));
1080 LayoutList::iterator end = layoutlist_.end();
1081 bool const ret = (it != end);
1082 layoutlist_.erase(it, end);
1087 // Load textclass info if not loaded yet
1088 bool TextClass::load(string const & path) const
1093 // Read style-file, provided path is searched before the system ones
1094 // If path is a file, it is loaded directly.
1095 FileName layout_file(path);
1096 if (!path.empty() && !layout_file.isReadableFile())
1097 layout_file = FileName(addName(path, name_ + ".layout"));
1098 if (layout_file.empty() || !layout_file.exists())
1099 layout_file = libFileSearch("layouts", name_, "layout");
1100 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1103 lyxerr << "Error reading `"
1104 << to_utf8(makeDisplayPath(layout_file.absFilename()))
1105 << "'\n(Check `" << name_
1106 << "')\nCheck your installation and "
1107 "try Options/Reconfigure..." << endl;
1114 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1117 layoutlist_.push_back(createBasicLayout(n, true));
1121 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1123 // FIXME The fix for the InsetLayout part of 4812 would be here:
1124 // Add the InsetLayout to the document class if it is not found.
1126 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1127 while (!n.empty()) {
1128 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1129 if (cit != cen && cit->first == n)
1131 size_t i = n.find(':');
1132 if (i == string::npos)
1136 return plain_insetlayout_;
1140 docstring const & TextClass::defaultLayoutName() const
1142 // This really should come from the actual layout... (Lgb)
1143 return defaultlayout_;
1147 Layout const & TextClass::defaultLayout() const
1149 return operator[](defaultLayoutName());
1153 bool TextClass::isDefaultLayout(Layout const & layout) const
1155 return layout.name() == defaultLayoutName();
1159 bool TextClass::isPlainLayout(Layout const & layout) const
1161 return layout.name() == plainLayoutName();
1165 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1167 static Layout * defaultLayout = NULL;
1169 if (defaultLayout) {
1170 defaultLayout->setUnknown(unknown);
1171 defaultLayout->setName(name);
1172 return *defaultLayout;
1175 static char const * s = "Margin Static\n"
1176 "LatexType Paragraph\n"
1179 "AlignPossible Left, Right, Center\n"
1180 "LabelType No_Label\n"
1182 istringstream ss(s);
1183 Lexer lex(textClassTags);
1185 defaultLayout = new Layout;
1186 defaultLayout->setUnknown(unknown);
1187 defaultLayout->setName(name);
1188 if (!readStyle(lex, *defaultLayout)) {
1189 // The only way this happens is because the hardcoded layout above
1191 LASSERT(false, /**/);
1193 return *defaultLayout;
1197 /////////////////////////////////////////////////////////////////////////
1199 // DocumentClassBundle
1201 /////////////////////////////////////////////////////////////////////////
1203 DocumentClassBundle::~DocumentClassBundle()
1205 for (size_t i = 0; i != documentClasses_.size(); ++i)
1206 delete documentClasses_[i];
1207 documentClasses_.clear();
1210 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1212 DocumentClass * dc = new DocumentClass(baseClass);
1213 documentClasses_.push_back(dc);
1214 return *documentClasses_.back();
1218 DocumentClassBundle & DocumentClassBundle::get()
1220 static DocumentClassBundle singleton;
1225 DocumentClass & DocumentClassBundle::makeDocumentClass(
1226 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1228 DocumentClass & doc_class = newClass(baseClass);
1229 LayoutModuleList::const_iterator it = modlist.begin();
1230 LayoutModuleList::const_iterator en = modlist.end();
1231 for (; it != en; it++) {
1232 string const modName = *it;
1233 LyXModule * lm = theModuleList[modName];
1235 docstring const msg =
1236 bformat(_("The module %1$s has been requested by\n"
1237 "this document but has not been found in the list of\n"
1238 "available modules. If you recently installed it, you\n"
1239 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1240 ExceptionMessage(WarningException,_("Module not available"),
1241 msg + _("Some layouts may not be available."));
1244 if (!lm->isAvailable()) {
1245 docstring const msg =
1246 bformat(_("The module %1$s requires a package that is\n"
1247 "not available in your LaTeX installation. LaTeX output\n"
1248 "may not be possible.\n"), from_utf8(modName));
1249 ExceptionMessage(WarningException, _("Package not available"), msg);
1251 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1252 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1253 docstring const msg =
1254 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1255 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1262 /////////////////////////////////////////////////////////////////////////
1266 /////////////////////////////////////////////////////////////////////////
1268 DocumentClass::DocumentClass(LayoutFile const & tc)
1273 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1275 LayoutList::const_iterator it = layoutlist_.begin();
1276 LayoutList::const_iterator end = layoutlist_.end();
1277 for (; it != end; ++it)
1278 if (it->latexname() == lay)
1284 bool DocumentClass::provides(string const & p) const
1286 return provides_.find(p) != provides_.end();
1290 bool DocumentClass::hasTocLevels() const
1292 return min_toclevel_ != Layout::NOT_IN_TOC;
1296 Layout const & DocumentClass::htmlTOCLayout() const
1298 if (html_toc_section_.empty()) {
1299 // we're going to look for the layout with the minimum toclevel
1300 TextClass::LayoutList::const_iterator lit = begin();
1301 TextClass::LayoutList::const_iterator const len = end();
1302 int minlevel = 1000;
1303 Layout const * lay = NULL;
1304 for (; lit != len; ++lit) {
1305 int const level = lit->toclevel;
1306 // we don't want Part
1307 if (level == Layout::NOT_IN_TOC || level < 0 || level >= minlevel)
1313 html_toc_section_ = lay->name();
1315 // hmm. that is very odd, so we'll do our best
1316 html_toc_section_ = defaultLayoutName();
1318 return operator[](html_toc_section_);
1322 /////////////////////////////////////////////////////////////////////////
1326 /////////////////////////////////////////////////////////////////////////
1328 ostream & operator<<(ostream & os, PageSides p)