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 string const & TextClass::prerequisites() const
1008 if (contains(prerequisites_, ',')) {
1009 vector<string> const pres = getVectorFromString(prerequisites_);
1010 prerequisites_ = getStringFromVector(pres, "\n\t");
1012 return prerequisites_;
1015 bool TextClass::hasLayout(docstring const & n) const
1017 docstring const name = n.empty() ? defaultLayoutName() : n;
1019 return find_if(layoutlist_.begin(), layoutlist_.end(),
1020 LayoutNamesEqual(name))
1021 != layoutlist_.end();
1025 bool TextClass::hasInsetLayout(docstring const & n) const
1029 InsetLayouts::const_iterator it = insetlayoutlist_.begin();
1030 InsetLayouts::const_iterator en = insetlayoutlist_.end();
1031 for (; it != en; ++it)
1038 Layout const & TextClass::operator[](docstring const & name) const
1040 LASSERT(!name.empty(), /**/);
1043 find_if(begin(), end(), LayoutNamesEqual(name));
1046 lyxerr << "We failed to find the layout '" << to_utf8(name)
1047 << "' in the layout list. You MUST investigate!"
1049 for (const_iterator cit = begin(); cit != end(); ++cit)
1050 lyxerr << " " << to_utf8(cit->name()) << endl;
1052 // we require the name to exist
1053 LASSERT(false, /**/);
1060 Layout & TextClass::operator[](docstring const & name)
1062 LASSERT(!name.empty(), /**/);
1064 iterator it = find_if(begin(), end(), LayoutNamesEqual(name));
1067 LYXERR0("We failed to find the layout '" << to_utf8(name)
1068 << "' in the layout list. You MUST investigate!");
1069 for (const_iterator cit = begin(); cit != end(); ++cit)
1070 LYXERR0(" " << to_utf8(cit->name()));
1072 // we require the name to exist
1073 LASSERT(false, /**/);
1080 bool TextClass::deleteLayout(docstring const & name)
1082 if (name == defaultLayoutName() || name == plainLayoutName())
1085 LayoutList::iterator it =
1086 remove_if(layoutlist_.begin(), layoutlist_.end(),
1087 LayoutNamesEqual(name));
1089 LayoutList::iterator end = layoutlist_.end();
1090 bool const ret = (it != end);
1091 layoutlist_.erase(it, end);
1096 // Load textclass info if not loaded yet
1097 bool TextClass::load(string const & path) const
1102 // Read style-file, provided path is searched before the system ones
1103 // If path is a file, it is loaded directly.
1104 FileName layout_file(path);
1105 if (!path.empty() && !layout_file.isReadableFile())
1106 layout_file = FileName(addName(path, name_ + ".layout"));
1107 if (layout_file.empty() || !layout_file.exists())
1108 layout_file = libFileSearch("layouts", name_, "layout");
1109 loaded_ = const_cast<TextClass*>(this)->read(layout_file);
1112 lyxerr << "Error reading `"
1113 << to_utf8(makeDisplayPath(layout_file.absFilename()))
1114 << "'\n(Check `" << name_
1115 << "')\nCheck your installation and "
1116 "try Options/Reconfigure..." << endl;
1123 void DocumentClass::addLayoutIfNeeded(docstring const & n) const
1126 layoutlist_.push_back(createBasicLayout(n, true));
1130 InsetLayout const & DocumentClass::insetLayout(docstring const & name) const
1132 // FIXME The fix for the InsetLayout part of 4812 would be here:
1133 // Add the InsetLayout to the document class if it is not found.
1135 InsetLayouts::const_iterator cen = insetlayoutlist_.end();
1136 while (!n.empty()) {
1137 InsetLayouts::const_iterator cit = insetlayoutlist_.lower_bound(n);
1138 if (cit != cen && cit->first == n)
1140 size_t i = n.find(':');
1141 if (i == string::npos)
1145 return plain_insetlayout_;
1149 docstring const & TextClass::defaultLayoutName() const
1151 // This really should come from the actual layout... (Lgb)
1152 return defaultlayout_;
1156 Layout const & TextClass::defaultLayout() const
1158 return operator[](defaultLayoutName());
1162 bool TextClass::isDefaultLayout(Layout const & layout) const
1164 return layout.name() == defaultLayoutName();
1168 bool TextClass::isPlainLayout(Layout const & layout) const
1170 return layout.name() == plainLayoutName();
1174 Layout TextClass::createBasicLayout(docstring const & name, bool unknown) const
1176 static Layout * defaultLayout = NULL;
1178 if (defaultLayout) {
1179 defaultLayout->setUnknown(unknown);
1180 defaultLayout->setName(name);
1181 return *defaultLayout;
1184 static char const * s = "Margin Static\n"
1185 "LatexType Paragraph\n"
1188 "AlignPossible Left, Right, Center\n"
1189 "LabelType No_Label\n"
1191 istringstream ss(s);
1192 Lexer lex(textClassTags);
1194 defaultLayout = new Layout;
1195 defaultLayout->setUnknown(unknown);
1196 defaultLayout->setName(name);
1197 if (!readStyle(lex, *defaultLayout)) {
1198 // The only way this happens is because the hardcoded layout above
1200 LASSERT(false, /**/);
1202 return *defaultLayout;
1206 /////////////////////////////////////////////////////////////////////////
1208 // DocumentClassBundle
1210 /////////////////////////////////////////////////////////////////////////
1212 DocumentClassBundle::~DocumentClassBundle()
1214 for (size_t i = 0; i != documentClasses_.size(); ++i)
1215 delete documentClasses_[i];
1216 documentClasses_.clear();
1219 DocumentClass & DocumentClassBundle::newClass(LayoutFile const & baseClass)
1221 DocumentClass * dc = new DocumentClass(baseClass);
1222 documentClasses_.push_back(dc);
1223 return *documentClasses_.back();
1227 DocumentClassBundle & DocumentClassBundle::get()
1229 static DocumentClassBundle singleton;
1234 DocumentClass & DocumentClassBundle::makeDocumentClass(
1235 LayoutFile const & baseClass, LayoutModuleList const & modlist)
1237 DocumentClass & doc_class = newClass(baseClass);
1238 LayoutModuleList::const_iterator it = modlist.begin();
1239 LayoutModuleList::const_iterator en = modlist.end();
1240 for (; it != en; it++) {
1241 string const modName = *it;
1242 LyXModule * lm = theModuleList[modName];
1244 docstring const msg =
1245 bformat(_("The module %1$s has been requested by\n"
1246 "this document but has not been found in the list of\n"
1247 "available modules. If you recently installed it, you\n"
1248 "probably need to reconfigure LyX.\n"), from_utf8(modName));
1249 ExceptionMessage(WarningException,_("Module not available"),
1250 msg + _("Some layouts may not be available."));
1253 if (!lm->isAvailable()) {
1254 docstring const msg =
1255 bformat(_("The module %1$s requires a package that is\n"
1256 "not available in your LaTeX installation. LaTeX output\n"
1257 "may not be possible.\n"), from_utf8(modName));
1258 ExceptionMessage(WarningException, _("Package not available"), msg);
1260 FileName layout_file = libFileSearch("layouts", lm->getFilename());
1261 if (!doc_class.read(layout_file, TextClass::MODULE)) {
1262 docstring const msg =
1263 bformat(_("Error reading module %1$s\n"), from_utf8(modName));
1264 throw ExceptionMessage(WarningException, _("Read Error"), msg);
1271 /////////////////////////////////////////////////////////////////////////
1275 /////////////////////////////////////////////////////////////////////////
1277 DocumentClass::DocumentClass(LayoutFile const & tc)
1282 bool DocumentClass::hasLaTeXLayout(std::string const & lay) const
1284 LayoutList::const_iterator it = layoutlist_.begin();
1285 LayoutList::const_iterator end = layoutlist_.end();
1286 for (; it != end; ++it)
1287 if (it->latexname() == lay)
1293 bool DocumentClass::provides(string const & p) const
1295 return provides_.find(p) != provides_.end();
1299 bool DocumentClass::hasTocLevels() const
1301 return min_toclevel_ != Layout::NOT_IN_TOC;
1305 Layout const & DocumentClass::htmlTOCLayout() const
1307 if (html_toc_section_.empty()) {
1308 // we're going to look for the layout with the minimum toclevel
1309 TextClass::LayoutList::const_iterator lit = begin();
1310 TextClass::LayoutList::const_iterator const len = end();
1311 int minlevel = 1000;
1312 Layout const * lay = NULL;
1313 for (; lit != len; ++lit) {
1314 int const level = lit->toclevel;
1315 // we don't want Part
1316 if (level == Layout::NOT_IN_TOC || level < 0 || level >= minlevel)
1322 html_toc_section_ = lay->name();
1324 // hmm. that is very odd, so we'll do our best
1325 html_toc_section_ = defaultLayoutName();
1327 return operator[](html_toc_section_);
1331 /////////////////////////////////////////////////////////////////////////
1335 /////////////////////////////////////////////////////////////////////////
1337 ostream & operator<<(ostream & os, PageSides p)